Python中HTTP POST请求的行为不一致

Jua*_*oto 6 python rest http urllib2 node.js

尝试在Python(WSGI)和NodeJS + Express应用程序之间发出POST请求.它们位于不同的服务器上.

问题在于,当使用不同的IP地址(即专用网络与公共网络)时,urllib2公共网络上的请求成功,但是对于专用网络的相同请求因a 502 Bad Gateway或者 失败而失败URLError [32] Broken pipe.

urllib2我正在使用的代码是这样的:

req = urllib2.Request(url, "{'some':'data'}", {'Content-Type' : 'application/json; charset=utf-8'})

res = urllib2.urlopen(req)

print f.read()
Run Code Online (Sandbox Code Playgroud)

现在,我还编写了这样的请求,使用requests:

r = requests.post(url, headers = {'Content-Type' : 'application/json; charset=utf-8'}, data = "{'some':'data'}")

print r.text
Run Code Online (Sandbox Code Playgroud)

得到200 OK回应.这种替代方法适用于两种网络.

我有兴趣urllib2了解我不知道的请求是否需要一些额外的配置,或者我是否需要查看可能缺少的某些网络配置(我不相信这种情况,因为备用请求方法有效,但我肯定是错的).

任何建议或指针将非常感谢.谢谢!

aba*_*ert 3

这里的问题是,正如奥斯汀·菲利普斯指出的那样,urllib2.Request构造函数的data参数:

\n\n
\n

可能是一个字符串,指定要发送到服务器的附加数据\xe2\x80\xa6应该是标准application/x-www-form-urlencodeddata中的缓冲区。urllib.urlencode() 函数采用二元组的映射或序列并返回此格式的字符串。

\n
\n\n

通过传递 JSON 编码的数据而不是 urlen 编码的数据,您可能会在某个地方混淆它。

\n\n

不过Request有一个方法add_data

\n\n
\n

将请求数据设置为数据。除 HTTP 处理程序 \xe2\x80\x94 之外的所有处理程序都会忽略它,并且它应该是一个字节字符串,并且会将请求更改为 POST 而不是 GET。

\n
\n\n

如果你使用这个,你可能也应该使用add_header它,而不是在构造函数中传递它,尽管文档中似乎没有具体提到这一点。

\n\n

所以,这应该有效:

\n\n
req = urllib2.Request(url)\nreq.add_data("{\'some\':\'data\'}")\nreq.add_header(\'Content-Type\', \'application/json; charset=utf-8\')\nres = urllib2.urlopen(req)\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

您在评论中说:

\n\n
\n

我不想在不找出为什么会出现这个问题的情况下就切换到请求,原因是可能存在一些更深层次的潜在问题,这可能会回来并导致更难以检测的问题稍后的。

\n
\n\n

如果您想找到深层的问题,您不会仅通过查看客户端源代码来做到这一点。弄清楚“为什么 X 有效但 Y 失败?”的第一步 使用网络代码的目的是准确计算出 X 和 Y 各自发送的字节数。然后你可以尝试缩小相关差异的范围,然后找出代码的哪一部分导致 Y 在相关位置发送错误的数据。

\n\n

您可以通过在服务上记录内容(如果您控制它)、运行 Wireshark 等来完成此操作,但对于简单情况,最简单的方法是 netcat。您需要man nc针对您的系统进行阅读(并且,在 Windows 上,您需要获取并安装 netcat,然后才能运行它),因为每个版本的语法都不同,但它总是很简单喜欢nc -kl 12345

\n\n

然后,在您的客户端中,更改要使用的 URLlocalhost:12345来代替主机名,它将连接到 netcat 并发送其 HTTP 请求,该请求将转储到终端。然后您可以复制并使用nc HOST 80并粘贴它来查看真实服务器的响应情况,并使用它来缩小问题的范围。或者,如果您遇到困难,至少您可以将数据复制并粘贴到您的 SO 问题中。

\n\n
\n\n

最后一件事:这几乎肯定与您的问题无关(因为您正在发送完全相同的数据并且requests它正在工作),但您的数据实际上不是有效的 JSON,因为它使用单引号而不是双引号引号。根据文档string定义为:

\n\n
string\n    ""\n    " chars "\n
Run Code Online (Sandbox Code Playgroud)\n\n

(这些文档也有很好的图形表示。)

\n\n

一般来说,除了非常简单的测试用例之外,您不想手动编写 JSON。在许多情况下(包括您的情况),您所要做的就是"\xe2\x80\xa6"json.dumps(\xe2\x80\xa6)所以这并不是一个严重的困难。所以:

\n\n
req = urllib2.Request(url)\nreq.add_data(json.dumps({\'some\':\'data\'}))\nreq.add_header(\'Content-Type\', \'application/json; charset=utf-8\')\nres = urllib2.urlopen(req)\n
Run Code Online (Sandbox Code Playgroud)\n\n

那么,它为什么有效呢?好吧,在 JavaScript 中,单引号字符串是合法的,反斜杠转义等其他内容在 JSON 中无效,并且任何使用受限 eval(或更糟糕的是原始 eval)进行解析的 JS 代码都将接受它。而且,由于很多人因此习惯编写糟糕的 JSON,因此许多浏览器的本机 JSON 解析器和其他语言的许多 JSON 库都有解决方法来允许常见错误。但你不应该依赖它。

\n