与Python中的HTTP POST请求不一致的行为
尝试在Python(WSGI)和NodeJS + Express应用程序之间发出POST请求。 他们在不同的服务器上。
问题是,当使用不同的IP地址(即专用networking与公用networking)时,公共networking上的urllib2
请求成功,但是对于专用networking的相同请求却失败,出现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()
现在,我也使用request来编写这样的requests
:
r = requests.post(url, headers = {'Content-Type' : 'application/json; charset=utf-8'}, data = "{'some':'data'}") print r.text
得到一个200 OK
回应。 这种替代方法适用于这两个networking。
我有兴趣了解是否有一些额外的configuration需要我不知道的urllib2
请求,或者如果我需要查看一些可能会丢失的networkingconfiguration(我不相信这是事实,因为替代请求方法起作用,但我肯定是错的)。
任何build议或指针与此将不胜感激。 谢谢!
这里的问题是,正如Austin Phillips指出的, urllib2.Request
的构造函数的data
参数:
可能是指定要发送到服务器的附加数据的string…
data
应该是标准应用程序/ x-www-form-urlencoded格式的缓冲区。 urllib.urlencode()函数采用2元组的映射或序列,并以此格式返回string。
通过传递它JSON编码的数据而不是urlencoded数据,你在某处混淆了它。
但是, Request
有一个方法add_data
:
将请求数据设置为数据。 除了HTTP处理程序之外,所有的处理程序都会忽略它 – 在那里它应该是一个字节string,并且会将请求更改为POST而不是GET。
如果你使用这个,你可能也应该使用add_header
而不是在构造函数中传递它,尽pipe在文档的任何地方都没有提到它。
所以,这应该工作:
req = urllib2.Request(url) req.add_data("{'some':'data'}") req.add_header('Content-Type', 'application/json; charset=utf-8') res = urllib2.urlopen(req)
在一个评论中,你说:
我不希望只是转而请求,却不知道为什么我会看到这个问题,可能会有一些更深层次的根本性问题,这些问题可能会回来,并在以后导致难以发现的问题。
如果你想find深层次的问题,你不会仅仅通过查看你的客户端来源来做到这一点。 找出“为什么X能工作但Y失败?”的第一步。 与networking代码是确切地找出什么字节X和Y每个发送。 然后你可以尝试缩小相关的区别,然后找出你的代码的哪一部分导致Y在相关位置发送错误的数据。
你可以通过在服务上logging事情(如果你控制它),运行Wireshark等等,但最简单的方法是netcat。 你需要为你的系统阅读man nc
(在Windows上,你需要先安装netcat,然后才能运行它),因为每个版本的语法都不一样,但是它总是像nc -kl 12345
一样简单nc -kl 12345
。
然后,在你的客户端中,将URL改为使用localhost:12345
代替主机名,它将连接到netcat并发送它的HTTP请求,并将其转储到terminal。 然后,您可以复制该文件并使用nc HOST 80
并将其粘贴,以查看真实服务器如何响应,并使用它来缩小问题的位置。 或者,如果您遇到困难,至less您可以将数据复制并粘贴到您的SO问题中。
最后一件事:这几乎肯定与您的问题无关(因为您发送的requests
数据完全相同,而且正在工作),但是您的数据实际上并不是有效的JSON,因为它使用单引号而不是双引号。 根据文档 , string
被定义为:
string "" " chars "
(文档也有很好的graphics表示。)
一般来说,除了非常简单的testing用例外,您不需要手动编写JSON。 在很多情况下(包括你的),你所要做的就是用json.dumps(…)
replace"…"
,所以这不是一个严重的困难。 所以:
req = urllib2.Request(url) req.add_data(json.dumps({'some':'data'})) req.add_header('Content-Type', 'application/json; charset=utf-8') res = urllib2.urlopen(req)
那么,为什么它工作? 那么,在JavaScript中,单引号的string是合法的,以及其他的东西,如在JSON中无效的反斜杠转义,并且任何使用restricted-eval(或更糟糕的是,eval)parsing的JS代码都会接受它。 而且,由于许多人习惯于编写不良的JSON,因此许多浏览器的本地JSONparsing器和其他语言的许多JSON库都有解决方法,可以解决常见的错误。 但是你不应该依赖这个。