如何在Python/Tornado中按RFC 5987规范编码Content-Disposition文件名?
在Python/Tornado中实现Content-Disposition头的filename编码(基于RFC 5987)
嘿,我刚好研究过这个问题,给你分享下实用的解决方案吧!
先理清楚基础逻辑
- 处理Content-Disposition头里的特殊字符(比如中文)文件名,RFC 5987定义了一套标准的编码规范,这是目前最可靠的解决方案
- 主流浏览器早在2012年11月就已经全面支持这个编码方式,不用太担心兼容性问题
Python/Tornado里的具体实现
目前Tornado确实没有内置的工具函数来做这件事,不过我们可以自己实现RFC 5987的编码逻辑,然后配合self.set_header来设置响应头。
第一步:实现编码函数
我们可以用Python标准库的urllib.parse来完成编码,写一个简单的工具函数:
import urllib.parse def encode_rfc5987_filename(filename): # 按照RFC 5987规范,用UTF-8编码文件名 encoded = urllib.parse.quote(filename, encoding='utf-8') # 返回符合规范的filename*参数格式 return f"filename*=UTF-8''{encoded}"
第二步:在Tornado请求处理器中使用
接下来在你的请求处理类里,调用这个函数生成响应头内容:
import tornado.web class FileDownloadHandler(tornado.web.RequestHandler): def get(self): # 你的原始文件名,比如包含中文或特殊字符 target_filename = "我的文档_2024.txt" # 构造符合RFC 5987的Content-Disposition头 disposition_header = f"attachment; {encode_rfc5987_filename(target_filename)}" # 设置响应头 self.set_header('Content-Disposition', disposition_header) # 这里添加返回文件内容的逻辑,比如读取本地文件并返回 # with open(target_filename, 'rb') as f: # self.write(f.read()) self.set_header('Content-Type', 'application/octet-stream')
额外的兼容性小技巧
如果你的服务需要兼容非常老旧的浏览器(比如IE8及更早版本),可以同时设置传统的filename参数和标准的filename*参数,这样新旧浏览器都能正常识别:
disposition_header = f"attachment; filename=\"{target_filename}\"; {encode_rfc5987_filename(target_filename)}"
不过现在这种老旧浏览器的使用场景已经极少,大部分情况下只用filename*就足够了。
内容的提问来源于stack exchange,提问作者Francesco Marchetti-Stasi
相关产品推荐
相关产品推荐

