[英]Parse multipart/form-data using cgi.FieldStorage; None keys
The following piece of code should be able to run in Python 2.7 and Python 3.x. 以下代码应该能够在Python 2.7和Python 3.x中运行。
from __future__ import unicode_literals
from __future__ import print_function
import cgi
try:
from StringIO import StringIO as IO
except ImportError:
from io import BytesIO as IO
body = """
--spam
Content-Disposition: form-data; name="param1"; filename=blob
Content-Type: binary/octet-stream
value1
--spam--
"""
parsed = cgi.FieldStorage(
IO(body.encode('utf-8')),
headers={'content-type': 'multipart/form-data; boundary=spam'},
environ={'REQUEST_METHOD': 'POST'})
print([key for key in parsed])
In Python 2.7 it runs fine and it outputs ['param1']
. 在Python 2.7中它运行正常并输出['param1']
。 In Python 3.4 however, it outputs [None]
. 但是在Python 3.4中,它输出[None]
。
I cannot get FieldStorage
to get a usable result in Python 3. I suspect something internally changed and I'm now using it wrong. 我无法让FieldStorage
在Python 3中获得可用的结果。我怀疑内部发生了一些变化,我现在正在使用它。 However I can't seem to figure out what. 但是我似乎无法弄清楚是什么。 Any help is appreciated. 任何帮助表示赞赏。
These changes will make your script work identically in both Python 2.7.x and 3.4.x: 这些更改将使您的脚本在Python 2.7.x和3.4.x中的工作方式完全相同:
(I will use these abbreviations for cgi.FieldStorage()
: Python 2.7.x: FS27 , Python 3.4.x: FS34 ) (我将使用cgi.FieldStorage()
这些缩写:Python 2.7.x: FS27 ,Python 3.4.x: FS34 )
1 - While FS27 handles the newline before the boundary correctly, that is not the case with FS34 so the solution is to start with your boundary( spam
) directly. 1 -虽然FS27边界之前正确处理新行,就是不与FS34的情况下,这样的解决方案是先从你的边界( spam
直接)。
body = """--spam
Content-Disposition: form-data; name="param1"; filename=blob
Content-type: binary/octet-stream
value1
--spam--
"""
2 - Quoting from cgi.py source (in FS34's definition comments): 2 - 从cgi.py 源引用(在FS34的定义注释中):
Arguments, all optional: 参数,全部可选:
fp : file pointer; fp:文件指针; default: sys.stdin.buffer (not used when the request method is GET) default:sys.stdin.buffer(请求方法为GET时不使用)
Can be : 1. a TextIOWrapper object 2. an object whose read() and readline() methods return bytes
The grey part is not present in FS27 definition, so, most of the differences between FS27 and FS34 lie in the handling of strings(FS27) and binary streams(FS34) . FS27定义中不存在灰色部分,因此FS27和FS34之间的大部分差异在于字符串(FS27)和二进制流(FS34)的处理 。
In this context, FS34 can easily mess the semantics of the parsed object, unless it is given proper directions on how to handle this correctly. 在这种情况下, FS34很容易混淆解析对象的语义,除非给出正确处理方法的正确指示。 Apparently, the headers
dictionary entry 'content-type': 'multipart/form-data; boundary=spam'
显然, headers
字典条目'content-type': 'multipart/form-data; boundary=spam'
'content-type': 'multipart/form-data; boundary=spam'
is not enough; 'content-type': 'multipart/form-data; boundary=spam'
还不够; you have to supply the message length information. 你必须提供消息长度信息。
You can achieve this, effectively , by adding a second entry in headers
: 您可以通过在headers
添加第二个条目来有效地实现此目的:
headers={'content-type': 'multipart/form-data; boundary=spam;',
'content-length': len(body)}
where the value for the content-length
key is the body
length (including the start/end boundaries). 其中content-length
键的值是body
长(包括起始/结束边界)。
These modifications, combined, lead to the desired result: 这些修改结合起来,产生了预期的结果:
$ python script.py
['param1']
$ python3 script.py
['param1']
As proof-of-concept , these are the returned parsed
objects from both FS27 and FS34 : 作为概念验证 ,这些是FS27和FS34返回的parsed
对象:
...
print(parsed)
...
yields: 收益率:
FieldStorage(None, None, [FieldStorage('param1', 'blob', 'value1')])
for FS27 , and 对于FS27 ,和
FieldStorage(None, None, [FieldStorage('param1', 'blob', b'value1')])
for FS34 . 对于FS34 。
In both Python 2.7 and Python 3.5 (not working in Python 3.4 for some reason), the desired output is returned by adding Content-Length
to the response body: 在Python 2.7和Python 3.5中(由于某种原因在Python 3.4中不起作用),通过向响应主体添加Content-Length
来返回所需的输出:
body = """
--spam
Content-Disposition: form-data; name="param1"; filename=blob
Content-Length: 6
Content-Type: binary/octet-stream
value1
--spam--
"""
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.