【问题标题】:How to return byte array so that it downloads as a zip file in the browser?如何返回字节数组以便在浏览器中下载为 zip 文件?
【发布时间】:2020-11-08 11:05:37
【问题描述】:

我在 S3 中有一个 zip 文件,我正试图将其返回给用户。最终结果是,当用户点击我的 API 时,它应该将这个 zip 文件下载到用户的计算机上。

这是我从 S3 获取数据的方式(也可以使用 s3.get_object 检索数据)

@pyramid_view.view_config(route_name='route_name', renderer='string')
async def get_data(request):

    res = await(func(request))
    return res



async def func(request):
url = s3_client.generate_presigned_url('get_object',
                                           Params={'Bucket': DEFAULT_BUCKET_NAME,
                                                   'Key': path},
                                           ExpiresIn=3600)
    response = urllib.request.urlopen(url)
    finalData = response.read()
return finalData

收到finalData 后,我将标题设置为

request.response.content_type = 'binary/octet-stream'
request.response.headers['Access-Control-Allow-Methods'] = 'POST, GET'
request.response.headers['Access-Control-Expose-Headers'] = 'X-filename'
request.response.headers['Content-Transfer-Encoding']='binary'
request.response.headers['X-filename'] = path
request.response.content_disposition = 'attachment;filename=try.zip'

然后从我的 API 返回 finalData

文件被下载,但是当我尝试打开它时,它说:

有人知道为什么会发生这种情况吗?对于flask app,它似乎工作得很好。我正在尝试在 API 网关中完成这项工作。

我试图读取通过十六进制编辑器下载的文件,它显示了这个

如果我这样做 responseFinal.decode(encoding="utf-8", errors="ignore") ,现在下载的文件看起来像这样(仍然没有解压缩)。 在十六进制编辑器中通过预签名 url 成功下载的文件看起来像。是否有一些我缺少的编码? (我尝试过 utf-8 解码,但 zip 文件失败)

【问题讨论】:

  • 无效 zip 文件的内容是什么?这可能会给你一个提示。尝试使用十六进制编辑器打开它。
  • 嘿@orlp,zip 文件包含一个 .json 文件和一个 .csv 文件。如果我通过预签名的 url 下载它(只需在浏览器中点击 url),它就会完美地下载文件。我实际上正在尝试开发一个 API 来将此数据返回给用户。
  • 你误解了我的评论。通过十六进制编辑器查看 try (1).zip 以查看它实际包含的内容,以提示出现了什么问题。
  • @orlp 用 try(1).zip 的内容和预期的样子更新了帖子。
  • 这看起来像 Python 显示二进制字符串的序列化表示,而不是实际的二进制数据。显示您用于将其写入文件的代码。问题可能就在那里。看起来您获取了二进制数据并执行了str(b"data"),这是错误的输出方式。

标签: python python-3.x


【解决方案1】:

想通了。问题是金字塔中的渲染器将数据转换为字符串格式。如果我们将数据添加到响应中,渲染器不会影响它。感谢@user120242 指导我朝这个方向发展。
我通过创建响应对象来修复它

async def func(request):
url = s3_client.generate_presigned_url('get_object',
                                           Params={'Bucket': DEFAULT_BUCKET_NAME,
                                                   'Key': path},
                                           ExpiresIn=3600)
    response = urllib.request.urlopen(url)
    finalData = response.read()
request.response.content_type = 'binary/octet-stream'
    request.response.headers['Access-Control-Allow-Methods'] = 'POST, GET'
    request.response.headers['Access-Control-Expose-Headers'] = 'X-filename'
    request.response.headers['Content-Transfer-Encoding'] = 'binary'
    request.response.headers['X-filename'] = path
    request.response.content_disposition = 'attachment;filename=try.zip'

request.response.body = finalData
return request.response

【讨论】:

    猜你喜欢
    • 2016-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-13
    • 1970-01-01
    • 1970-01-01
    • 2021-07-13
    相关资源
    最近更新 更多