Python FastAPI StreamingResponse 不编码特殊字符

问题描述 投票:0回答:1

我尝试做一个 FastAPI,通过

StreamingResponse()
类触发文件下载(参见 FastAPI 页面)。这部分其实还可以。

我的问题是,当文件包含重音(例如 é)或其他特殊字符时,它似乎无法很好地对其进行编码。

例如,当存在

é
时,在 CSV 中它将转换为
é
,在 JSON 中将转换为
\u00e9

我的代码是这样的:

  • 对于 JSON
# API CONTENT
# ...

return StreamingResponse(io.StringIO(json.dumps(data)), headers={"Content-Disposition": "filename=filename.json")
  • 对于 CSV
# API CONTENT
# ...

return StreamingResponse(io.StringIO(pandas.DataFrame(data).to_csv(index=False)), headers={"Content-Disposition": f"filename=filename.csv"})

为了修复编码,我还尝试了:

  • 在CSV部分添加

    media_type="text/csv; charset=utf-8"
    但没有成功。

  • 在标题部分添加

    "Content-Type": "application/octet-stream; charset=utf-8"
    ,但也没有成功。

  • 尝试用

    StreamingResponse
    替换
    Response
    .

有人已经遇到过这种问题吗?我想准确地说,将其添加到

StreamingResponse
之前的内容已编码良好。

这是要测试的代码示例:

from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import pandas as pd
import io
import json

app = FastAPI()

# Exemple de données avec des caractères spéciaux
data = [
    {"éète": "test", "age": 10},
    {"éète": "test2", "age": 5},
]

@app.get("/download_json")
async def download_json():
    return StreamingResponse(io.StringIO(json.dumps(data)), headers={"Content-Disposition": "filename=data.json"})

@app.get("/download_csv")
async def download_csv():
    return StreamingResponse(io.StringIO(pd.DataFrame(data).to_csv(index=False)), headers={"Content-Disposition": "filename=data.csv"})```
python character-encoding fastapi starlette
1个回答
0
投票

Python 的

json
模块默认将非 ASCII 和 Unicode 字符转换为
\u
转义序列。为了避免以这种方式转换非 ASCII 或 Unicode 字符,在将数据编码为 JSON 时,可以将
ensure_ascii
函数的
json.dumps()
标志设置为
False
。同样,当使用 Panda 的 DataFrame
to_json()
to_csv()
函数时,您需要确保分别将它们与
force_ascii=False
encoding='ascii'
参数一起使用。

关于使用

StreamingResponse
,我建议查看这个答案以及其中包含的所有参考资料,以便了解是否以及何时应该使用它。在您的情况下,如问题中给出的示例所示,不需要,但您应该返回自定义
Response
,如上面链接的答案中所述。

最后,如这个答案这个答案中所述,您可以定义

Content-Disposition
标头,以便数据可以在浏览器中查看下载到客户端设备,使用以下任一方法:

headers = {'Content-Disposition': 'inline; filename="out.json"'}

headers = {'Content-Disposition': 'attachment; filename="out.json"'}

请查看链接的答案以了解更多详细信息。

工作示例

from fastapi import FastAPI, Response
import pandas as pd
import json


app = FastAPI()


# Exemple de données avec des caractères spéciaux
data = [
    {"éète": "test", "age": 10},
    {"éète": "test2", "age": 5},
]

    
@app.get("/1")
async def get_json():
    headers = {"Content-Disposition": 'inline; filename="out.json"'}
    return Response(
        json.dumps(data, ensure_ascii=False),
        headers=headers,
        media_type="application/json",
    )


@app.get("/2")
async def get_json_from_df():
    headers = {"Content-Disposition": 'inline; filename="out.json"'}
    return Response(
        pd.DataFrame(data).to_json(orient="records", force_ascii=False),
        headers=headers,
        media_type="application/json",
    )


@app.get("/3")
async def get_csv_from_df():
    headers = {"Content-Disposition": 'inline; filename="out.json"'}
    return Response(
        pd.DataFrame(data).to_csv(index=False, encoding="ascii"),
        headers=headers,
        media_type="application/json",
    )
© www.soinside.com 2019 - 2024. All rights reserved.