目的

  • リクエストに対してマルチバイトファイル名でファイルダウンロードさせる。

httpでファイルダウンロード

  • httpの決まり事として、ファイルをダウンロードさせたいときは、レスポンスに Content-Dispositionヘッダを含めれば良いことになっています。
Content-Disposition: attachment; filename="filename.txt"

Djangoの記述

  • 下記で期待通り動きます。ただし、ファイル名がascii文字の場合です。
from django.http import HttpResponse
def index(request):
    content = 'body1'
    response = HttpResponse(content, content_type='text/plain')
    response['Content-Disposition'] = 'attachment; filename="filename.txt"'
    return response

マルチバイト文字の場合

  • 単純に記述した場合。
response['Content-Disposition'] = 'attachment; filename="ファイル.txt"'
  • ヘッダは下記のようになります。UTF8-MIME-Base64ぽい。
  • 実際、email.header.Headerを使ってエンコードしているようです。
Content-Disposition: =?utf-8?b?YXR0YWNobWVudDsgZmlsZW5hbWU9IuODleOCoeOCpOODqy50eHQi?=
  • これは正しい挙動なのか調べていませんが、とりあえず手元のWebブラウザではファイルをダウンロードするように解釈してくれないようです。

対応方法

  • ファイル名部分だけをURLエンコードしてセットします。
import urllib.parse
response['Content-Disposition'] = 'attachment; filename="{fn}"'.format(fn=urllib.parse.quote("ファイル.txt"))
  • ヘッダは下記のようになり、Webブラウザも期待通り、ファイルダウンロードレスポンスとして動作してくれます。
Content-Disposition: attachment; filename="%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB.txt"

facebook slideshare rubygems github qiita