我正在从事一种个人云项目,它允许上传和下载文件(具有类似谷歌的搜索功能)。后端是用python编写的(使用aiohttp),而我使用react.js网站作为客户端。上载文件时,后端将其存储在文件系统中,并使用其sha256哈希对其进行重命名。原始名称和一些其他元数据存储在其旁边(说明等)。当用户下载文件时,我使用multipart为其提供服务,我希望用户使用原始名称而不是散列来获取文件,事实上my-cool-image.png
比a14e0414-b84c-4d7b-b0d4-49619b9edd8a
更便于用户使用。但我无法做到这一点(无论我怎么做,下载文件都是用散列调用的)
这是我的密码:
async def download(self, request):
if not request.username:
raise exceptions.Unauthorized("A valid token is needed")
data = await request.post()
hash = data["hash"]
file_path = storage.get_file(hash)
dotfile_path = storage.get_file("." + hash)
if not os.path.exists(file_path) or not os.path.exists(dotfile_path):
raise exceptions.NotFound("file <{}> does not exist".format(hash))
with open(dotfile_path) as dotfile:
dotfile_content = json.load(dotfile)
name = dotfile_content["name"]
headers = {
"Content-Type": "application/octet-stream; charset=binary",
"Content-Disposition": "attachment; filename*=UTF-8''{}".format(
urllib.parse.quote(name, safe="")
),
}
return web.Response(body=self._file_sender(file_path), headers=headers)
不过,有一件事我想说清楚:有时我会收到一条警告(在客户端)说Resource interpreted as Document but transferred with MIME type application/octet-stream
。我不知道文件的MIME类型,因为它们是由用户提供的,但我尝试使用image/png(我使用存储在服务器上的png图像进行了测试)。文件没有被下载(它显示在浏览器中,这不是我想要的),并且文件名仍然是它的哈希,因此它对我的问题没有帮助
以下是后端的全部源代码: https://git.io/nexmind-node 以及前端: https://git.io/nexmind-client
编辑: 我收到了Julien Castiaux的第一个答案,所以我尝试实现它,尽管它看起来更好,但它并不能解决我的问题(我仍然有完全相同的行为):
async def download(self, request):
if not request.username:
raise exceptions.Unauthorized("A valid token is needed")
data = await request.post()
hash = data["hash"]
file_path = storage.get_file(hash)
dotfile_path = storage.get_file("." + hash)
if not os.path.exists(file_path) or not os.path.exists(dotfile_path):
raise exceptions.NotFound("file <{}> does not exist".format(hash))
with open(dotfile_path) as dotfile:
dotfile_content = json.load(dotfile)
name = dotfile_content["name"]
response = web.StreamResponse()
response.headers['Content-Type'] = 'application/octet-stream'
response.headers['Content-Disposition'] = "attachment; filename*=UTF-8''{}".format(
urllib.parse.quote(name, safe="") # replace with the filename
)
response.enable_chunked_encoding()
await response.prepare(request)
with open(file_path, 'rb') as fd: # replace with the path
for chunk in iter(lambda: fd.read(1024), b""):
await response.write(chunk)
await response.write_eof()
return response
来自aiohttp3文档
在发送(可能非常大的)文件时,您宁愿使用
aiohttp.web.StreamResponse
。使用StreamResponse
,您可以完全控制传出的http响应流:标头操作(包括文件名)和分块编码希望有帮助
相关问题 更多 >
编程相关推荐