お疲れ様です。
今回はFastAPIのファイルダウンロードで日本語のファイル名をダウンロードする際の注意点についてまとめました。
ちょうど1年前くらいにFastAPIでファイルダウンロードをするAPIを作成していました。 その際はファイル名を半角英数字のみで作成していたため気づかなかったのですが、この時のコードだと日本語を含むファイル名のファイルをダウンロードしようとするとエラーが起こります。
ソースコード
今回もエラー再現のためにデモページとAPIを作成しました。
以下GitHubに残してありますので必要があればご確認ください。
実行してページを開くとこんな感じです。

エラー内容と対処方法
エラーはFastAPIで作成したAPIエンドポイントのレスポンスの内容によるものです。
以下エラーが起こるパターンとエラーを解消したパターンを記載します。
エラーが発生する書き方
import io from fastapi import FastAPI from fastapi.responses import StreamingResponse app = FastAPI() @app.get("/download") def download_from_df() -> StreamingResponse: """DataFrameを指定ファイル形式でダウンロードするAPI (ローカルにファイル保存せず、データをファイル化して返す) """ stream = io.StringIO() sample_df.to_csv(stream, encoding='utf-8', index=False) stream.seek(0) filename = "日本語ファイルサンプル.csv" media_type = "text/csv" return StreamingResponse( content=stream, media_type=media_type, headers={"Content-Disposition": f"attachment; filename={filename}"} )
ページ上のボタンを押してダウンロードしようとするとこのように「Internal Server Error」で表示されます。

Python側の表示を見ると下記のエラーが出ています。
これはStreamingResponseの処理中に起こっており、ファイル名に日本語を含む場合に再現します。
非ASCII文字が含まれていることが原因のようです。
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 21-31: ordinal not in range(256)
![]()
正しい書き方
import io from urllib.parse import quote # 追加 from fastapi import FastAPI from fastapi.responses import StreamingResponse app = FastAPI() @app.get("/download") def download_from_df() -> StreamingResponse: """DataFrameを指定ファイル形式でダウンロードするAPI (ローカルにファイル保存せず、データをファイル化して返す) """ stream = io.StringIO() sample_df.to_csv(stream, encoding='utf-8', index=False) stream.seek(0) filename = "日本語ファイルサンプル.csv" media_type = "text/csv" return StreamingResponse( content=stream, media_type=media_type, headers={"Content-Disposition": f"attachment; filename*=UTF-8''{quote(filename)}"} # ここを修正 )
urllib.parse.quote()を使用します。
こちらを適用させることで日本語を含む文字列(非ASCII文字を含む文字列)をURLエンコーディングしてファイル名に設定しています。
実際に実行するとこんな感じ。
日本語の部分が%から始まる特殊な文字に置き換えられています。

これで正常にダウンロードできます。実際にダウンロードすると変換する前の元の日本語ファイル名なっていることがわかります。

参考
下記を参考にしました。併せてご参照ください。
ありがとうございました。


















