Flask下如何处理Requests上传中⽂⽂件名的问题
⼀、问题的由来
最近有个项⽬,叫做⽂档服务资源中⼼,类似于七⽜,为各个业务系统提供统⼀的⽂件资源服务,包括⽂件的存储、操作管理、下载、预览等。在做⽂件存储的时候,遇到了这个当指定上传的⽂件名为中⽂时,Flask框架的服务端⽆法解析成⽂件,⽽是当成⼀般的表单数据处理。我们在⽂件存储的实现架构如下图:
客户端业务系统(Python开发的)通过调⽤python-sdk中的上⽂⽂件API上传⽂件。按照requests这个类库上传⽂件的格式要求,必须指明⽂件的⽂件名。所以,在API开发完成之后,当上传的⽂件的⽂件名是中⽂的时候,测试没通过。
⼆、代码解析
客户端测试代码:
请注意,在files变量中,file对应的元组值的第⼀个参数“⼗三五”发展规划.docx”就是⽂件名,是中⽂格式。
服务端代码(简化后):
注意,在ption中的代码,判断是否获取⽂件成功。
运⾏:
先运⾏服务端代码,然后运⾏测试代码。结果如下:
进⼊调试模式,查看request变量的值,重点关注files跟form属性。如下图:
从上图可以,files的属性为空,⽽把file当成了form数据的属性,属性的值为⽂件的⼆进制内容数据。
三、问题缘由的查
(1.)下载fiddler抓包⼯具。发现requests向flask⽹站服务传递如下数据。
特别注意,红框中的filename*这⼀段。
(2.)读Flask的源代码,特别注意Flask对上传⽂件的解析与处理。发现位于werkzeug下的formparser.py⾥的parse_lines⽅法中判断语句(位于⽂件的413⾏)
可以得出结论,Flask是根据名称为filename的键来判断Requests传递过来的数据是否是⽂件内容。⽽在上⾯通过fiddler抓包⼯具可知,Requests传递了filename*这个键的名称,多了⼀个*号。所以,Flas
k认为不是传递的⽂件,从⽽当成了⼀般属性处理。
(3.)那Requests为什么会传递filename*这样的键呢。再次跟踪并阅读Requests的源代码。返现Requests会对filename做编码的特殊处理。代码位于requestsàpackagesàurllib3—>fields.py(第22⾏的format_header_param⽅法)。
对不是ascii编码的内容,进⾏了rfc 2231编码,并组织成key*= rfc 2231这种格式。所以就有了上述的filename*这种格式的键值对。四、解决办法
有三种解决办法。
(1.)修改Requests的源代码
requestsàpackagesàurllib3—>fields.py—>format_header_param⽅法的以下代码
改成
(2.)修改Flask的源代码
werkzeug下的formparser.py⾥的parse_lines⽅法中的413⾏开始的以下代码
flask下载
改成
并导⼊相应的包。
(3.)修改调⽤Request的post⽅法时files变量的filename赋值,将其改成英⽂,⽐如设置成固定的file_name,⽽将真正的filename(最好带有后缀)当成data参数中的键名为file_name(根据项⽬情况,⾃由定义)的值传递给服务端,服务端去读取file_name对应的值就⾏。实现代码如下:
总结:修改Flask、requests类库的源代码不太理想,不便于部署,⽽且可能会发⽣其他意想不到的问题。建议采⽤第3中折中解决办法。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。