HOWTO · Flask

使用 Flask 下載檔案

通過這個解釋,我們將學習如何在 Flask 中的 send_file 函式的幫助下建立一個可下載的連結以將檔案下載為附件。

本頁內容

若要讓 Flask 頁面上的連結下載檔案,請定義一個會回傳 send_file(path, as_attachment=True) 的路由,再用 url_for 將範本中的連結指向該路由。檔案必須存在於路由所使用的路徑。

從 Flask 下載路由回傳檔案

send_file 會建立承載檔案的回應。檢視函式必須回傳這個回應;若呼叫 send_file 時沒有加上 return,Flask 就不會收到預期的回應。設定 as_attachment=True 後,Flask 會將檔案以附件形式傳送,讓瀏覽器提供下載,而不是將檔案當成頁面顯示。

從範本連結至下載路由

使用 url_for 指定路由的端點名稱。Flask 預設會以檢視函式名稱作為端點,因此下方的連結和函式都使用 download_file。URL 路徑(/download)與端點名稱是不同的項目:Flask 在轉譯範本時會透過 url_for 查找端點。GET 連結無法修正拼錯或尚未註冊的端點。

範本應放在與 app.py 同一層、名為 templates 的資料夾中:
本節中的程式碼以及顯示的標籤或輸出仍為英文。

<h2>Download the sample file</h2>
<p><a href="{{ url_for('download_file') }}">Download</a></p>

使用可靠的檔案路徑與附件設定

從 app.root_path 建立路徑,讓路徑以應用程式目錄為基準,而不受 shell 目前工作目錄影響。這個本機範例會在 app.py 旁建立一個小型文字檔;請將該路徑換成你要提供的檔案路徑。不要接受來自 URL 或表單的任意檔案系統路徑,再直接傳給 send_file。

預設下載檔名會取自路徑,因此這個範例會將檔案提供為 sample.txt。若儲存的檔名與下載時顯示的名稱不同,可在 send_file 中明確指定 download_name。請自行控管選用的路徑,並在傳送前確認檔案可供存取;相較於訪客提供的路徑,根據可信的應用程式設定組合出的路徑更容易檢查與管理。

將以下內容存成 app.py。程式會在應用程式旁建立範本與範例檔案,接著使用 Flask 的測試用戶端發出請求,不必啟動伺服器程序:
本節中的程式碼以及顯示的標籤或輸出仍為英文。

from pathlib import Path

from flask import Flask, render_template, send_file

app = Flask(__name__)
template_dir = Path(app.root_path) / "templates"
template_dir.mkdir(exist_ok=True)
(template_dir / "index.html").write_text(
    '<p><a href="{{ url_for(\'download_file\') }}">Download</a></p>',
    encoding="utf-8",
)
SAMPLE_FILE = Path(app.root_path) / "sample.txt"
SAMPLE_FILE.write_text("A file served by Flask.\n", encoding="utf-8")


@app.route("/")
def index():
    return render_template("index.html")


@app.route("/download")
def download_file():
    return send_file(SAMPLE_FILE, as_attachment=True)


if __name__ == "__main__":
    with app.test_client() as client:
        print(client.get("/").get_data(as_text=True).strip())
        response = client.get("/download")
        print(response.status_code)
        print(response.headers["Content-Disposition"])
        print(response.get_data(as_text=True), end="")

範本會將 download_file 解析為 /download,而測試用戶端會向該路由發出請求。執行腳本時,它會輸出轉譯後的連結、回應狀態、附件標頭和檔案內容。輸出區塊中的可見標籤因範例須逐字保留而維持英文。附件標頭可用來確認瀏覽器收到的是下載回應;檢查本文則可確認伺服器提供了選定的檔案。

執行並確認完整範例

如果專案環境尚未安裝 Flask,請先安裝,再執行 python app.py,於本機確認轉譯後的連結和下載回應。若要在瀏覽器中試用相同的路由,請使用 flask --app app run 啟動 Flask 開發伺服器,開啟 http://127.0.0.1:5000/,然後選取 Download。瀏覽器應會下載 sample.txt;直接瀏覽 /download 也會取得相同的附件。按 Ctrl+C 停止伺服器。偵錯模式僅供本機開發使用;請勿在可從公開網路連線的伺服器上啟用互動式偵錯工具。