使用 urllib2 进行 POST 调用而不是 GET

Posted

技术标签:

【中文标题】使用 urllib2 进行 POST 调用而不是 GET【英文标题】:Making a POST call instead of GET using urllib2 【发布时间】:2011-09-14 23:09:13 【问题描述】:

关于 urllib2 和 POST 调用有很多东西,但我遇到了一个问题。

我正在尝试对服务进行简单的 POST 调用:

url = 'http://myserver/post_service'
data = urllib.urlencode('name' : 'joe',
                         'age'  : '10')
content = urllib2.urlopen(url=url, data=data).read()
print content

当我发送数据时,我可以看到服务器日志,它说我正在执行 GET 调用 urlopen 的参数。

库引发 404 错误(未找到),这对于 GET 调用是正确的,POST 调用处理良好(我也在尝试在 html 表单中使用 POST)。

【问题讨论】:

顺便说一句,服务器应该返回 405。 @IgnacioVazquez-Abrams 这个文档说 405 不适合 GET 和 HEAD 请求...developer.mozilla.org/en-US/docs/Web/HTTP/… 【参考方案1】:

requests 模块可以减轻您的痛苦。

url = 'http://myserver/post_service'
data = dict(name='joe', age='10')

r = requests.post(url, data=data, allow_redirects=True)
print r.content

【讨论】:

OP 询问“使用 urllib2”? 虽然可行,但 OP 说想使用 urllib2 而不是 requests,这是一个 3rd 方库。使用 3rd 方库可能会有所帮助,但也会使代码不可移植,这可能是 OP 最初关心的问题。 确实,这对我的情况绝对没用。 一句话:Poratbility 一个非常有趣的单词选择【参考方案2】:

分阶段进行,并修改对象,如下所示:

# make a string with the request type in it:
method = "POST"
# create a handler. you can specify different handlers here (file uploads etc)
# but we go for the default
handler = urllib2.HTTPHandler()
# create an openerdirector instance
opener = urllib2.build_opener(handler)
# build a request
data = urllib.urlencode(dictionary_of_POST_fields_or_None)
request = urllib2.Request(url, data=data)
# add any other information you want
request.add_header("Content-Type",'application/json')
# overload the get method function with a small anonymous function...
request.get_method = lambda: method
# try it; don't forget to catch the result
try:
    connection = opener.open(request)
except urllib2.HTTPError,e:
    connection = e

# check. Substitute with appropriate HTTP code.
if connection.code == 200:
    data = connection.read()
else:
    # handle the error case. connection.read() will still contain data
    # if any was returned, but it probably won't be of any use

这种方式允许您扩展为发出PUTDELETEHEADOPTIONS 请求,只需替换方法的值,甚至将其包装在一个函数中。根据您要执行的操作,您可能还需要不同的 HTTP 处理程序,例如用于多文件上传。

【讨论】:

这读起来太可怕了;很难找到代码。 我认为查看详细方式很有用,也许不是大多数情况,但有时需要调整一些特殊的东西。【参考方案3】:

阅读urllib Missing Manual。下面是一个简单的 POST 请求示例。

url = 'http://myserver/post_service'
data = urllib.urlencode('name' : 'joe', 'age'  : '10')
req = urllib2.Request(url, data)
response = urllib2.urlopen(req)
print response.read()

正如@Michael Kent 建议的那样,请考虑requests,这很棒。

编辑: 这就是说,我不知道为什么将数据传递给 urlopen() 不会导致 POST 请求;这应该。我怀疑您的服务器正在重定向或行为异常。

【讨论】:

谢谢@Rob,我尝试了你的建议,但也没有用。原来我在 URL 中遗漏了一个斜杠。 @Akim 没问题。好想法@Gregg :) 您也可以将数据传递给 GET 请求,urllib2.urlopen 无法从这个上下文中知道您想要什么,这就是原因。 刚刚测试过这个,效果很好。谢谢@RobCowie!【参考方案4】:

试试这个:

url = 'http://myserver/post_service'
data = urllib.urlencode('name' : 'joe',
                         'age'  : '10')
req = urllib2.Request(url=url,data=data)
content = urllib2.urlopen(req).read()
print content

【讨论】:

【参考方案5】:

这可能之前已经回答过:Python URLLib / URLLib2 POST。

您的服务器可能正在执行从 http://myserver/post_servicehttp://myserver/post_service/ 的 302 重定向。执行 302 重定向时,请求从 POST 变为 GET(请参阅Issue 1401)。尝试将url 更改为http://myserver/post_service/

【讨论】:

是的!我在 URL 中缺少一个斜杠。我正在投票并标记为已接受。谢谢!!【参考方案6】:

如果您提供数据参数(就像您正在做的那样),它应该发送 POST:

来自文档: “提供数据参数时,HTTP 请求将是 POST 而不是 GET”

所以.. 添加一些调试输出以查看客户端发生了什么。

你可以修改你的代码,然后再试一次:

import urllib
import urllib2

url = 'http://myserver/post_service'
opener = urllib2.build_opener(urllib2.HTTPHandler(debuglevel=1))
data = urllib.urlencode('name' : 'joe',
                         'age'  : '10')
content = opener.open(url, data=data).read()

【讨论】:

【参考方案7】:
url="https://myserver/post_service"
data["name"] = "joe"
data["age"] = "20"
data_encoded = urllib2.urlencode(data)
print urllib2.urlopen(url + "?" + data_encoded).read()

这可能会有所帮助

【讨论】:

这是一个 GET 请求,而不是一个 POST

以上是关于使用 urllib2 进行 POST 调用而不是 GET的主要内容,如果未能解决你的问题,请参考以下文章

将类型切换为 POST 而不是 GET 后 JSON 调用不起作用

verilog中,对一个模块的多次调用,比如前一个调用还没有结束的情况下,就再次调用,后者是不是会覆盖前者?

为啥不总是使用 HTTP post 进行 ajax 调用?

如何将 emacs 设置为在 verilog 模式下使用 3 个空格而不是制表符?

我们如何在 OpenTest 中进行使用 formdata 而不是 json 的 POST 服务调用?

使用POST调用而不是使用curl将信息发送到服务器