LoginSignup
2
0

More than 1 year has passed since last update.

FastAPIでファイルダウンロードさせる時のContent-Dispositionヘッダーの公開方法

Posted at

FastAPIでファイルダウンロードさせる時の Content-Disposition ヘッダーの公開方法

ファイルダウンロードを実装する際に、レスポンスのヘッダー情報から filename を取得する必要があるのだが、FastAPIの場合は、デフォルトでは Content-Disposition ヘッダーを返却しません。

デフォルトで公開される CORS セーフリストレスポンスヘッダーは 7 つだけ

CORS セーフリストレスポンスヘッダー

レスポンスヘッダー
Cache-Control
Content-Language
Content-Length
Content-Type
Expires
Last-Modified
Pragma

FastAPIで、 Access-Control-Expose-Headers に Content-Disposition ヘッダーの公開を許可する

FastAPI アプリケーションでは CORSMiddleware を使用して、CORSに関する設定ができます。

Access-Control-Expose-Headers レスポンスヘッダーで、レスポンスの一部としてどのヘッダーを公開するかを、その名前を列挙する必要があります。

CORSMiddlewareで、Access-Control-Expose-Headersを設定するには、

expose_headers に、公開したいレスポンスヘッダーを列挙します。デフォルトは [] です。

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

origins = [
    "http://localhost.tiangolo.com",
    "https://localhost.tiangolo.com",
    "http://localhost",
    "http://localhost:8080",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
    expose_headers=["Content-Disposition"] # ここ!
)

FileResponse をレスポンスする

from fastapi import FastAPI
from fastapi.responses import FileResponse

file_name = "見積書20221206124057.xlsx"
file_path = "/tmp/見積書20221206124057.xlsx"
app = FastAPI()


@app.get("/")
async def main():
    return FileResponse(
        path = file_path,
        filename = file_name
        )

レスポンスヘッダーとして、公開される

スクリーンショット 2022-12-07 13.40.00.png

axiosとfile-saverで、ダウンロードして保存させる例

import axios from 'axios';
import saveAs from 'file-saver';

function authHeaders(token, config = {}) {
    config.headers = {
        Authorization: `Bearer ${token}`,
    };
    return config;
}

function getFileName(contentDisposition) {
    let fileName = contentDisposition.substring(contentDisposition.indexOf("''") + 2,
        contentDisposition.length
    );
    //デコードするとスペースが"+"になるのでスペースへ置換します
    fileName = decodeURI(fileName).replace(/\+/g, " ");

    return fileName;
}

const instance = axios.create({
    baseURL: process.env.VUE_APP_API_URL,
});

/**
 * 見積エクセルダウンロード
 * @param {*} token
 * @param {*} id
 * @returns response
 */
var id = 1;

instance.get(`/downloads/quotation/excel/${id}`, authHeaders(token, {
            responseType: 'blob'
        })).then(response => {
            const blob = new Blob([response.data], {
                type: response.data.type
            });

            //レスポンスヘッダからファイル名を取得します
            const contentDisposition = response.headers["Content-Disposition"];
            const fileName = getFileName(contentDisposition)

            //ダウンロードします
            saveAs(blob, fileName);
        });

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0