Python 无法通过http.client正确重新连接

Python 无法通过http.client正确重新连接,python,http,https,bots,telegram-bot,Python,Http,Https,Bots,Telegram Bot,我有一个电报机器人,它不断地向电报API发出更新请求 我偶尔会遇到这样的错误: 18-12-16 12:12:37: error: Traceback (most recent call last): File "/home/pi/MuseBot/main.py", line 157, in <module> main() File "/home/pi/MuseBot/main.py", line 34, in main updates = HANDLER.m

我有一个电报机器人,它不断地向电报API发出更新请求

我偶尔会遇到这样的错误:

18-12-16 12:12:37: error: Traceback (most recent call last):
  File "/home/pi/MuseBot/main.py", line 157, in <module>
    main()
  File "/home/pi/MuseBot/main.py", line 34, in main
    updates = HANDLER.makeRequest("getUpdates", {"timeout": REQUEST_DELAY, "offset": lastOffset})
  File "/home/pi/MuseBot/functions.py", line 42, in makeRequest
    response = self.con.getresponse()
  File "/usr/lib/python3.5/http/client.py", line 1198, in getresponse
    response.begin()
  File "/usr/lib/python3.5/http/client.py", line 297, in begin
    version, status, reason = self._read_status()
  File "/usr/lib/python3.5/http/client.py", line 258, in _read_status
    line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
  File "/usr/lib/python3.5/socket.py", line 576, in readinto
    return self._sock.recv_into(b)
  File "/usr/lib/python3.5/ssl.py", line 937, in recv_into
    return self.read(nbytes, buffer)
  File "/usr/lib/python3.5/ssl.py", line 799, in read
    return self._sslobj.read(len, buffer)
  File "/usr/lib/python3.5/ssl.py", line 583, in read
    v = self._sslobj.read(len, buffer)
OSError: [Errno 113] No route to host
当出现问题时,我调用这个函数:

    def reconnect(self):
        self.con.close()
        self.con = http.client.HTTPSConnection(URL, 443)
然后,我使用以下方法使用此处理程序发出请求:

    def makeRequest(self, cmd, data={}):
        jsonData = json.dumps(data)
        try:
            self.con.request("POST", REQUEST_URL+cmd, jsonData, HEADERS)
        except:
            debug("An error occurred while carrying out the API request", 1)

        response = self.con.getresponse()
        decodedResponse = json.loads(response.read().decode())
        if not decodedResponse["ok"]:
            debug("reponse: {}".format(decodedResponse), 3)
            raise ApiError(decodedResponse["error_code"])
            return False

        return decodedResponse["result"]
(APIRROR只是一个从Exception构造的类,我使用它在处理崩溃时将其与其他错误区分开来。) 每当出现上述错误时,我都会自动
重新连接
。但是每个后续的
makeRequest
调用都会产生以下错误:

18-12-16 12:13:02: notice: An error occurred while carrying out the API request
18-12-16 12:13:02: error: Traceback (most recent call last):
  File "/home/pi/MuseBot/main.py", line 157, in <module>
    main()
  File "/home/pi/MuseBot/main.py", line 23, in main
    metaData = HANDLER.makeRequest("getMe")
  File "/home/pi/MuseBot/functions.py", line 42, in makeRequest
    response = self.con.getresponse()
  File "/usr/lib/python3.5/http/client.py", line 1194, in getresponse
    response = self.response_class(self.sock, method=self._method)
  File "/usr/lib/python3.5/http/client.py", line 235, in __init__
    self.fp = sock.makefile("rb")
AttributeError: 'NoneType' object has no attribute 'makefile'
会解决它,但显然不会


我不知道如何在不创建错误循环的情况下自动重启我的机器人。非常感谢您的帮助。

亲爱的@JThistle请不要把这件事放在心上,但您的makeRequest中有一些错误,请阅读我在代码中的注释,然后再看一个可以实现您期望的效果的示例

您的代码:

def makeRequest(self, cmd, data={}):
    jsonData = json.dumps(data)
    try:
        self.con.request("POST", REQUEST_URL+ cmd, jsonData, HEADERS)
    except:
        # this is you main bug you do not rerise the exception so you
        # never actually reconnect
        debug("An error occurred while carrying out the API request", 1)

    # so your program follows to this step and the socket is closed when you try
    # to read from it, hence the second exception
    response = self.con.getresponse()

    decodedResponse = json.loads(response.read().decode())
    if not decodedResponse["ok"]:
        debug("reponse: {}".format(decodedResponse), 3)
        raise ApiError(decodedResponse["error_code"])
        # this is wrong you can not reach this return, raise exception ends execution
        # and goes up the stack until it will be caught or will crash the program
        return False

    return decodedResponse["result"]
这将重新设置异常,以便实际重新连接:

# python uses snake case not camel case, it might seem silly but pytonistas are
# easily annoyed bunch
def make_request(self, cmd, data=None):
    # it is risky to use a reference type as default argument
    # https://docs.python-guide.org/writing/gotchas/
    data = data or {}
    json_data = json.dumps(data)

    try:
        self.con.request("POST", REQUEST_URL + cmd, json_data, HEADERS)
    except:
        debug("An error occurred while carrying out the API request", 1)
        raise  # important

    response = self.con.getresponse()

    decoded_response = json.loads(response.read().decode())
    # if the 'ok' is not present in the response string you will get 'KeyError'
    # so use .get("ok") to get None instead
    if not decoded_response.get("ok"):
        debug("reponse: {}".format(decoded_response), 3)
        error = decoded_response.get("error_code")
        # what if the "error_code" not in the response, response could be empty ?
        raise ApiError(error)

    # again response could be malformed and you will get "KeyError" if
    # "result" is not present
    return decoded_response["result"]

首先,不使用snake case不是一个bug。但我会尝试引发异常,看看是否有效,谢谢。它还没有崩溃,但那是因为它实际上还没有遇到“无路由到主机”错误。我现在要接受这个答案。你可以测试它是否有效。使用mock中的补丁函数将异常注入con.request,然后您将看到发生了什么。不需要等待原始错误发生。你确定你的重新连接功能真的重新连接了吗?因为套接字的默认值始终为“无”,在我看来,您可能正在尝试重新连接,但服务器仍处于关闭状态,或者由于某种原因不接受您的连接,因此套接字尚未真正初始化。
def makeRequest(self, cmd, data={}):
    jsonData = json.dumps(data)
    try:
        self.con.request("POST", REQUEST_URL+ cmd, jsonData, HEADERS)
    except:
        # this is you main bug you do not rerise the exception so you
        # never actually reconnect
        debug("An error occurred while carrying out the API request", 1)

    # so your program follows to this step and the socket is closed when you try
    # to read from it, hence the second exception
    response = self.con.getresponse()

    decodedResponse = json.loads(response.read().decode())
    if not decodedResponse["ok"]:
        debug("reponse: {}".format(decodedResponse), 3)
        raise ApiError(decodedResponse["error_code"])
        # this is wrong you can not reach this return, raise exception ends execution
        # and goes up the stack until it will be caught or will crash the program
        return False

    return decodedResponse["result"]
# python uses snake case not camel case, it might seem silly but pytonistas are
# easily annoyed bunch
def make_request(self, cmd, data=None):
    # it is risky to use a reference type as default argument
    # https://docs.python-guide.org/writing/gotchas/
    data = data or {}
    json_data = json.dumps(data)

    try:
        self.con.request("POST", REQUEST_URL + cmd, json_data, HEADERS)
    except:
        debug("An error occurred while carrying out the API request", 1)
        raise  # important

    response = self.con.getresponse()

    decoded_response = json.loads(response.read().decode())
    # if the 'ok' is not present in the response string you will get 'KeyError'
    # so use .get("ok") to get None instead
    if not decoded_response.get("ok"):
        debug("reponse: {}".format(decoded_response), 3)
        error = decoded_response.get("error_code")
        # what if the "error_code" not in the response, response could be empty ?
        raise ApiError(error)

    # again response could be malformed and you will get "KeyError" if
    # "result" is not present
    return decoded_response["result"]