使用urllib2无法设置内容类型为application/json。

13
这个小家伙:
import urllib2
import simplejson as json

opener = urllib2.build_opener()
opener.addheaders.append(('Content-Type', 'application/json'))
response = opener.open('http://localhost:8000',json.dumps({'a': 'b'}))

产生以下请求(如ngrep所示):
sudo ngrep -q -d lo '^POST .* localhost:8000'

T 127.0.0.1:51668 -> 127.0.0.1:8000 [AP]
  POST / HTTP/1.1..Accept-Encoding: identity..Content-Length: 10..Host: localhost:8000..Content-Type: application/x-www-form-urlencoded..Connection: close..User-Agent:
   Python-urllib/2.7....{"a": "b"} 

我不想要那个 Content-Type: application/x-www-form-urlencoded,我明确地表示我要 ('Content-Type', 'application/json')
这是怎么回事?!
4个回答

16

如果您想设置自定义标头,则应使用Request对象:

import urllib2
import simplejson as json

opener = urllib2.build_opener()
req = urllib2.Request('http://localhost:8000', data=json.dumps({'a': 'b'}),
      headers={'Content-Type': 'application/json'})
response = opener.open(req)

1
谢谢,但这并不能解决我的问题。代码已经实现(遗留),我只需要更改“Content-Type”。为什么“opener.addheaders.append”不像预期的那样工作? - blueFast
2
如果没有添加相应的标头,则addheaders中的标头将被添加,但是如果您使用data参数,则内容类型已经隐式设置为默认值(x-www-form-urlencoded)。在这种情况下,它优先于addheaders中的标头。 - mata
这种行为有点出乎意料。不管怎样,感谢您的建议,我已经成功让它工作了。谢谢! - blueFast

2

我也遇到了同样的问题,并写出了以下这个小技巧:

import urllib2
import simplejson as json

class ChangeTypeProcessor(BaseHandler):
    def http_request(self, req):
        req.unredirected_hdrs["Content-type"] = "application/json"
        return req

opener = urllib2.build_opener()
self.opener.add_handler(ChangeTypeProcessor())
response = opener.open('http://localhost:8000',json.dumps({'a': 'b'}))

你只需要添加一个处理 HTTP 请求的句柄,该句柄会替换之前由 OpenerDirector 添加的标头。

0

Python版本:Python 2.7.15 我在urllib2.py:1145中发现:

        for name, value in self.parent.addheaders:
            name = name.capitalize()
            if not request.has_header(name):
                request.add_unredirected_header(name, value)

...
    def has_header(self, header_name):
        return (header_name in self.headers or
                header_name in self.unredirected_hdrs)

否则,application/x-www-form-urlencoded 已经在未重定向的头文件中,并且不会被覆盖。
您可以像这样解决:

import urllib.request
from http.cookiejar import CookieJar

import json

url = 'http://www.baidu.com'
req_dict = {'k': 'v'}

cj = CookieJar()
handler = urllib.request.HTTPCookieProcessor(cj)
opener = urllib.request.build_opener(handler)

req_json = json.dumps(req_dict)
req_post = req_json.encode('utf-8')
headers = {}
#headers['Content-Type'] = 'application/json'
req = urllib.request.Request(url=url, data=req_post, headers=headers)

#urllib.request.install_opener(opener)
#res = urllib.request.urlopen(req)
# or
res = opener.open(req)

res = res.read().decode('utf-8')

-1
问题在于标题名称的大小写。您应该使用Content-type而不是Content-Type

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接