代码之家  ›  专栏  ›  技术社区  ›  deadvoid

如何在请求(或urllib3.response)中获取完整的服务器响应消息?

  •  1
  • deadvoid  · 技术社区  · 6 年前

    400 Bad Request . 请求版本为 2.19.1 v4 ),就像 spreadsheets.values.append spreadsheets.values.batchUpdate , spreadsheets.values.update

    我已经浪费了好几个小时来确保我已经形成了正确的数据结构,但毫无效果,只有到那时我才意识到我没有从API服务器得到完整的响应消息。

    requests.Response 从中返回的对象 r = request.Request('https://httpbin.org') 是从一个 requests.HTTPAdapter 对象,它又是 urllib3.response.HTTPResponse . 所以我试着用 r.reason , r.raw._original_response r.raw._body , r.raw.msg 它只给了我对象引用; None (或者只是空字符串)。

    长话短说,我放弃了一段时间;当我回到它,我意识到我应该尝试使用谷歌的API浏览器,我一直忽视,结果它出现了 响应中有一条错误消息,400错误不是由于任何错误的有效负载/数据结构表单造成的。

    {   "error": {
        "code": 400,
        "message": "Invalid data[0]: Requested writing within range [mysheet!A3:AH3], but tried writing to row [4]",
        "status": "INVALID_ARGUMENT"   } 
    }
    

    我在调试来自请求的连接响应时出错了吗&实际上,有一种方法可以在请求中从服务器获取完整的原始消息,比如curl中的完整调试模式?或者,这个消息实际上只在API请求来自googleapi浏览器时发送?

    2 回复  |  直到 6 年前
        1
  •  2
  •   Samuel Liew cicero lopes    6 年前

    a closed issue in requests repo 从去年起,题为“建议:提高地位,以包括响应机构,如果有一个”的发布 westover ,他在信中写道:

    他还提供了一个小的变通功能,这成为讨论转向的原因的基础 a pull request discussion

    import requests
    from requests.exceptions import HTTPError
    def expanded_raise_for_status(res):
        """
        Take a "requests" response object and expand the raise_for_status method to return more helpful errors
        @param res:
        @return: None
        """
        try:
            res.raise_for_status()
        except HTTPError as e:
            if res.text:
                raise HTTPError('{} Error Message: {}'.format(str(e.message), res.text))
            else:
               raise e
        return
    

    我将此应用于我现有的类&本质上是 jwodder 还指出,它扩展/劫持 Response.raise_for_status() 调用 HTTPError(RequestsException) raise_for_status() 由用户用来提供来自服务器响应的错误消息,通常以 assert response.status_code == 200, raise_for_status() Response.text (或 content / json <self.status_code, self.reason, self.url> 也就是说 400 Bad Requests <url>

    def raise_for_status(self):
        """Raises stored :class:`HTTPError`, if one occurred."""
    
        http_error_msg = ''
        if isinstance(self.reason, bytes):
            # We attempt to decode utf-8 first because some servers
            # choose to localize their reason strings. If the string
            # isn't utf-8, we fall back to iso-8859-1 for all other
            # encodings. (See PR #3538)
            try:
                reason = self.reason.decode('utf-8')
            except UnicodeDecodeError:
                reason = self.reason.decode('iso-8859-1')
        else:
            reason = self.reason
    
        if 400 <= self.status_code < 500:
            http_error_msg = u'%s Client Error: %s for url: %s' % (self.status_code, reason, self.url)
    
        elif 500 <= self.status_code < 600:
            http_error_msg = u'%s Server Error: %s for url: %s' % (self.status_code, reason, self.url)
    
        if http_error_msg:
            raise HTTPError(http_error_msg, response=self)
    

    this reply 他进一步阐述了为什么他认为它值得一个特性,但是pull请求被拒绝了,我认为维护人员也有优点),考虑到模块的流行性和广泛的使用原因,如果不慎重/谨慎地使用,这可能会导致其他异常或更复杂的情况。

        2
  •  1
  •   jwodder    6 年前

    您要查找的错误消息位于响应正文中。可以使用 response.text response.json() ,因为特定的主体是JSON)。如果,正如你的自我回答所暗示的,你想从一个由 raise_for_status() ,您只需通过异常 response 属性: exception.response.text exception.response.json() .