如何编码HTTP头的UTF8文件名? (Python,Django)

我有HTTP标题的问题,他们用ASCII编码,我想提供一个下载名称可以是非ASCII的文件的视图。

response['Content-Disposition'] = 'attachment; filename="%s"' % (vo.filename.encode("ASCII","replace"), ) 

我不想使用静态文件来处理与非ASCII文件名相同的问题,但在这种情况下,文件系统会出现问题,并且是文件名编码。 (我不知道目标操作系统。)

我已经尝试urllib.quote(),但它引发了KeyErrorexception。

可能我做错了,但也许是不可能的。

这是一个常见问题。

没有可互操作的方式来做到这一点。 一些浏览器实现专有扩展(IE,Chrome),其他实现RFC 2231(Firefox,Opera)。

请参阅http://greenbytes.de/tech/tc2231/上的testing案例。;

更新:截至2012年11月,所有当前的桌面浏览器都支持RFC 6266和RFC 5987(Safari> = 6,IE> = 9,Chrome,Firefox,Opera,Konqueror)中定义的编码。

不要在Content-Disposition中发送文件名。 跨浏览器(*)无法使非ASCII标头参数工作。

相反,只发送“内容处置:附件”,并将文件名保留为URL编码的UTF-8string,并放在URL的尾部(PATH_INFO)中,供浏览器默认使用。 浏览器可以更加可靠地处理UTF-8 URL,而不是使用Content-Disposition进行处理。

(*:实际上,甚至连当前的标准都没有说明它应该如何完成,因为RFC 2616,2231和2047之间的关系非常不正常,Julian正试图在规范级别上清除它。在遥远的将来。)

请注意,在2011年, RFC 6266 (尤其是附录D)对此问题进行了考虑,并提出了具体的build议。

也就是说,您只能使用ASCII字符发送filename* ,然后使用RFC 5987格式的文件名作为文件名。

通常这看起来像filename="my-resume.pdf"; filename*=UTF-8''My%20R%C3%A9sum%C3%A9.pdf filename="my-resume.pdf"; filename*=UTF-8''My%20R%C3%A9sum%C3%A9.pdf ,其中Unicode文件名(“MyRésumé.pdf”)被编码成UTF-8,然后被编码为百分号(注意,不要使用+作为空格)。

请确实阅读RFC 6266和RFC 5987(或者使用一个强大且经过testing的库,为您抽象出这个库),因为我的总结缺乏重要的细节。

黑客:

 if (Request.UserAgent.Contains("IE")) { // IE will accept URL encoding, but spaces don't need to be, and since they're so common.. filename = filename.Replace("%", "%25").Replace(";", "%3B").Replace("#", "%23").Replace("&", "%26"); } 

我可以说,我已经成功地使用了指定使用电子邮件表单( RFC 2231 )编码的头文件的更新( RFC 5987 )格式。 我想出了以下基于django-sendfile项目代码的解决scheme。

 import unicodedata from django.utils.http import urlquote def rfc5987_content_disposition(file_name): ascii_name = unicodedata.normalize('NFKD', file_name).encode('ascii','ignore').decode() header = 'attachment; filename="{}"'.format(ascii_name) if ascii_name != file_name: quoted_name = urlquote(file_name) header += '; filename*=UTF-8\'\'{}'.format(quoted_name) return header # eg # request['Content-Disposition'] = rfc5987_content_disposition(file_name) 

我只用Django 1.8Python 3.4上testing了我的代码。 所以django-sendfile中的类似解决scheme可能更适合你。

Django的追踪器中有一个长期的票据承认这一点,但尚未提出补丁。 所以不幸的是,这与使用强大的经过testing的库是如此接近,请让我知道是否有更好的解决scheme。