使用Python发送原始数据
我正在玩弄Google Checkout API,想把它整合进一个Django应用里。我需要用基本的HTTP认证把数据发送到Google。我用curl
测试了这个,像这样:
curl -d "$(cat mytest.xml)" -u username:password https://url
这样可以把我的测试XML文件的内容发送到Google,而且运行得很好!
但是把这行简单的代码转到Python时,我遇到了一些问题。我尝试了几种不同的方法(比如httplib2、urllib2、pycurl)来用密码连接并发送数据,但返回的结果总是400 BAD REQUEST。
有没有Python的方式可以把文本块发送到一个需要HTTP基本认证的服务器?我快要撞墙了。
抱歉没有附上任何代码。这里是我一些最常见的尝试。在每个例子中,DATA
是一个XML字符串,而URL
、USERNAME
和PASSWORD
是固定的。
req = urllib2.Request(URL)
req.add_header("Authorization", "Basic %s" % base64.encodestring('%s:%s'%(USERNAME, PASSWORD)))
u = urllib2.urlopen(req, DATA)
这给了我一个可爱的HTTP Error 400: Bad Request
passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
passman.add_password(None, URL, USERNAME, PASSWORD)
authhandler = urllib2.HTTPBasicAuthHandler(passman)
opener = urllib2.build_opener(authhandler)
urllib2.install_opener(opener)
pagehandle = urllib2.urlopen(URL, DATA)
这返回了HTTP Error 401: Unauthorized
pycurl.global_init(pycurl.GLOBAL_DEFAULT)
c = pycurl.Curl()
c.setopt(pycurl.URL, URL)
c.setopt(pycurl.USERPWD, "%s:%s" % (USERNAME,PASSWORD))
c.setopt(pycurl.POST, 1)
c.setopt(pycurl.HTTPHEADER, ["Content-type: text/xml"])
c.setopt(pycurl.POSTFIELDS, DATA)
b = StringIO.StringIO()
c.setopt(pycurl.WRITEFUNCTION, b.write)
c.perform()
似乎在把DATA
字符串作为POST字段时遇到了麻烦。我尝试用urllib.urlencode()
以不同的方式处理DATA,但
h = httplib2.Http()
h.add_credentials(USERNAME, PASSWORD)
print = h.request(URL, "POST", body=base64.encodestring(DATA))
凭证似乎没有任何作用——我从Google那里得到了一个未授权的消息。
还有更多尝试,但都是基于这些。
3 个回答
Voidspace 有一篇很棒的文章,讲的是如何用 urllib2 实现基本的身份验证。我在下面复制了相关的代码片段,并把它改成了使用 POST 方法。
import urllib2
theurl = 'http://www.someserver.com/toplevelurl/somepage.htm'
username = 'johnny'
password = 'XXXXXX'
passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
passman.add_password(None, theurl, username, password)
authhandler = urllib2.HTTPBasicAuthHandler(passman)
opener = urllib2.build_opener(authhandler)
urllib2.install_opener(opener)
pagehandle = urllib2.urlopen(theurl, open("mytext.xml").read())
不过没有看到你的代码,很难说你为什么会收到 400 的响应。
在编辑我的帖子,想要加入一些源代码的时候,我决定再试试 httplib2
这个库(主要是因为它相对较小,而且看起来也不错),结果发现它的 一个大漏洞,就是它的 add_credentials(..)
方法实际上并没有任何作用。你可以通过指定头信息来解决这个问题(就像我用 urllib2
时那样),方法如下:
resp, content = httplib2.Http().request(URL, "POST", body=DATA, headers={
"Authorization": "Basic %s" % base64.encodestring('%s:%s' %(USERNAME, PASSWORD)
})
这样就可以正常工作了。
我之前也遇到过类似的问题,特别是在使用标准库的包时,直到有人推荐了一个很棒的库——requests。这个库直接支持基本的Http认证和其他认证方式,使用起来非常方便!而且它的接口设计得既漂亮又简单,真让人爱不释手!
requests.post(url, data=DATA, headers=HEADERS_DICT, auth=(username, password))
它还支持很多其他必要的功能,比如HTTPS、摘要认证等等。如果你有需要的话,真的可以去看看...