当urllib3 http.request(' PUT',...)成功时,python requests.put()失败。是什么赋予了?

时间:2017-08-18 09:12:46

标签: python python-requests confluence-rest-api

我正在尝试使用python请求来访问Atlassian Confluence REST API。

我已经成功调用了GET api,但是当我调用PUT更新汇合页面时,它返回200,但没有更新页面。

我使用chrome :: YARC来验证API是否正常工作(它是什么)。经过一段时间试图调试它,我恢复尝试使用urllib3,它工作正常。

我真的很想使用请求,但我不能在生活中解决这个问题。经过数小时和数小时的尝试调试,谷歌等等。

我正在运行Mac / Python3:

$ uname -a
Darwin mylaptop.local 16.7.0 Darwin Kernel Version 16.7.0: Thu Jun 15 17:36:27 PDT 2017; root:xnu-3789.70.16~2/RELEASE_X86_64 x86_64
$ python3 --version
Python 3.6.1

这是我的代码,它显示了我尝试这三种方式(两个请求和一个urllib3):

def update(self, spaceKey, pageTitle, newContent, contentType='storage'):
    if contentType not in ('storage', 'wiki', 'plain'):
        raise ValueError("Invalid contentType={}".format(contentType))

    # Get current page info
    self._refreshPage(spaceKey, pageTitle) # I retrieve it before I update it.
    orig_version = self.version

    # Content already same as requested content. Do nothing
    if self.wiki == newContent:
        return

    data_dict = {
        'type' : 'page',
        'version' : {'number' : self.version + 1},
        'body'  : {
            contentType : {
                'representation' : contentType,
                'value' : str(newContent)
            }
        }
    }
    data_json = json.dumps(data_dict).encode('utf-8')

    put = 'urllib3' #for now until I figure out why requests.put() doesn't work
    enable_http_logging()
    if put == 'requests':
        r = self._cs.api.content(self.id).PUT(json=data_dict)
        r.raise_for_status()
    elif put == 'urllib3':
        urllib3.disable_warnings() # I know, you can quit your whining now!!!
        headers = { 'Content-Type' : 'application/json;charset=utf-8' }
        auth_header = urllib3.util.make_headers(basic_auth=":".join(self._cs.session.auth))
        headers = {**headers, **auth_header}
        http = urllib3.PoolManager()
        r = http.request('PUT', str(self._cs.api.content(self.id)), body=data_json, headers=headers)
    else:
        raise ValueError("Huh? Unknown put type: {}".format(put))
    enable_http_logging(False)

    # Verify page was updated
    self._refreshPage(spaceKey, pageTitle) # Check for changes
    if self.version != orig_version + 1:
        raise RuntimeError("Page not updated. Still at version {}".format(self.version))
    if self.wiki != newContent:
        raise RuntimeError("Page version updated, but not content.")

任何帮助都会很棒。

更新1:添加请求转储

-----------START-----------
PUT http://confluence.myco.com/rest/api/content/101904815
User-Agent: python-requests/2.18.4
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Content-Length: 141
Content-Type: application/json
Authorization: Basic <auth-token-here>==

b'{"type": "page", "version": {"number": 17}, "body": {"storage": {"representation": "storage", "value": "new body here version  version 17"}}}'

2 个答案:

答案 0 :(得分:2)

  

请求永远不会回到PUT(Bug ???)

您所观察到的是requests与网络浏览器一致的行为:使用GET请求对HTTP 302重定向做出反应。

From Wikipedia

  

使用此代码的响应邀请用户代理(例如Web浏览器)对位置字段中指定的新URL发出第二个相同的请求。

     

(...)

     

许多网络浏览器以违反此标准的方式实施此代码,将新请求的请求类型更改为GET,而不管原始请求中使用的类型(例如POST)

     

(...)

     

因此,RFC 2616的更新会更改定义,以允许用户代理将POST重写为GET。

所以这种行为与RFC 2616一致。我认为我们不能说这两个库中哪一个行为“更正确”。

答案 1 :(得分:0)

请求和urllib3模块处理从http切换到https的方式看起来不同。 (见上面的@Kos回答)。这是我在检查调试日志时发现的。

所以我想在@JonClements建议我发送响应转储后。在做了一些研究之后,我发现了魔术运行以启用对请求和urllib3的调试(参见here)。

在查看两者的差异时,我注意到他们被重定向到我的公司合并网站的http到https:

urllib3:

DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): confluence.myco.com
DEBUG:urllib3.connectionpool:http://confluence.myco.com:80 "PUT /rest/api/content/101906196 HTTP/1.1" 302 237
DEBUG:urllib3.util.retry:Incremented Retry for (url='http://confluence.myco.com/rest/api/content/101906196'): Retry(total=2, connect=None, read=None, redirect=None, status=None)
INFO:urllib3.poolmanager:Redirecting 
    http://confluence.myco.com/rest/api/content/101906196 -> 
    https://confluence.myco.com/rest/api/content/101906196
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): confluence.myco.com
DEBUG:urllib3.connectionpool:https://confluence.myco.com:443 "PUT /rest/api/content/101906196 HTTP/1.1" 200 None

请求尝试使用我的PUT,然后在重定向后转到GET:

DEBUG:urllib3.connectionpool:http://confluence.myco.com:80 "PUT /rest/api/content/101906196 HTTP/1.1" 302 237
DEBUG:urllib3.connectionpool:https://confluence.myco.com:443 "GET /rest/api/content/101906196 HTTP/1.1" 200 None

请求永远不会回到PUT

我将我的初始网址从http:改为https:一切正常。