【问题标题】:Not possible to set content-type to application/json using urllib2无法使用 urllib2 将内容类型设置为 application/json
【发布时间】:2012-12-17 18:48:49
【问题描述】:

这个小宝贝:

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')

这是怎么回事?!

【问题讨论】:

    标签: python json post urllib2


    【解决方案1】:

    如果您想设置自定义标题,您应该使用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)
    

    【讨论】:

    • 谢谢,但这并不能解决我的问题。代码已经实现(遗留),我只需要更改Content-Type。为什么opener.addheaders.append 没有按预期工作?
    • addheaders 中的标头仅在未添加相应标头时才添加,但如果您使用 data 参数,则内容类型已隐式设置为默认值(x-www-form -urlencoded)。在这种情况下,这优先于 addheaders 中的标头。
    • 这种行为有点出乎意料。无论如何,多亏了你的建议,我才能让它工作。谢谢!
    【解决方案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 之前添加的标头。

    【讨论】:

      【解决方案3】:

      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已经在unredirected_hdrs中,不会被覆盖

      你可以解决

      
      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')
      

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-02-28
          • 2019-03-01
          • 2021-01-04
          • 2017-04-27
          • 1970-01-01
          • 2015-10-09
          • 2023-03-06
          相关资源
          最近更新 更多