如何在不使用 CGI 的情况下在 python3.x 中获取 POST "data"变量?



当我尝试在python3.x cgi脚本中调用cgi.FieldStorage()时,我得到以下错误:

[Traceback: error in module x on line y]:
    cgi.FieldStorage()
File "/usr/lib64/python3.3/cgi.py", line 553, in __init__
    self.read_single()
File "/usr/lib64/python3.3/cgi.py", line 709, in read_single
    self.read_binary()
File "/usr/lib64/python3.3/cgi.py", line 731, in read_binary
    self.file.write(data)
TypeError: must be str, not bytes

我如何从ajax调用得到我的POST data变量?

示例ajax调用:
function (param) {
    $.ajax({
       type: "POST",
       url: "/cgi-bin/mycgi.py/TestMethod",
       data: JSON.stringify({"foo": "bar"}),
       contentType: "application/json; charset=utf-8",
       dataType: "json",
       success: function (result) {
           alert("Success " + result);
       },
       error: function () {
           alert("Failed");
       }
    });
}

根据http://lucumr.pocoo.org/2013/7/2/the-updated-guide-to-unicode/:

"There are also some special cases in the stdlib where strings are 
very confusing. The cgi.FieldStorage module which WSGI applications are 
sometimes still using for form data parsing is now treating QUERY_STRING 
as surrogate escaping, but instead of using utf-8 as charset for the URLs 
(as browsers) it treats it as the encoding returned by 
locale.getpreferredencoding(). I have no idea why it would do that, but 
it's incorrect. As workaround I recommend not using cgi.FieldStorage for 
query string parsing."


解决这个问题的方法是使用sys.stdin.read读取POST数据参数。然而请注意,如果您的cgi应用程序可以挂起,如果它期望读取的东西,没有发送。这可以通过读取HTTP报头中的字节数来解决:

#!/usr/bin/env python3
import os, sys, json
data = sys.stdin.read(int(os.environ.get('HTTP_CONTENT_LENGTH', 0)))
# To get data in a native python dictionary, use json.loads
if data:
    print(list(json.loads(data).keys())) # Prints out keys of json
# (You need to wrap the .keys() in list() because it would otherwise return 
#  "dict_keys([a, b, c])" instead of [a, b, c])

您可以在这里阅读更多关于CGI的内部信息:http://oreilly.com/openbook/cgi/ch04_02.html

接受的答案不适合我,没有返回数据(使用Windows Server 2012 &Python 3.4)。

当然,我很感激它可能对其他人有用,但我还是想把这篇文章贴出来,以防它能帮助到任何和我有同样经历的人。

在搜罗了许多类似的问题之后&相关的博客文章,以及我自己测试不同的方法,对我来说,获胜的组合是:

totalBytes=int(os.environ.get('HTTP_CONTENT_LENGTH'))
reqbin=io.open(sys.stdin.fileno(),"rb").read(totalBytes)

这两行是所有我需要接收原始二进制数据(图像,音频文件等),然后转储到一个文件。

如果你想把接收到的数据转换成字符串,你可以使用:

reqstr=reqbin.decode("utf-8")

最后,为了满足问题的要求,您可以将其解析为JSON,使用:

thejson=json.loads(reqstr)

我真的希望这能帮助那些无法找到其他方法的人!

在我的情况下,我tcpdump -x -X从JavaScript发送的数据,并注意到text/plainContent-type头正在发送。所以我把它设置为application/x-www-form-urlencoded推荐在这里,解决了这个问题。

最新更新