2016-01-12 1 views
1

Создаю сеанс, используя requests.Session(). По какой-то причине серверная сторона закрывает это соединение, поэтому мне нужно снова подключиться. Проблема в том, что этот сеанс используется во многих местах, поэтому мне интересно, возможно ли пересоздать TCP-соединение, но сохранить объект сеанса, чтобы я все еще мог его использовать?Возможно ли обновление сеанса в запросах?

Пример:

s = requests.Session() 

class B: 
    def __init__(self, session): 
     self._session = session 

    def get(self): 
     self._session.get('some_url') 

b1 = B(s) 
b2 = B(s) 
b3 = B(s) 

# some get calls 
... 
# then connection is closed 

# some get calls 
... 

Если бы я мог сохранить объект seesion, нет необходимости заменять каждый _session в каждом B инстанции.

Журнал ошибок:

Traceback (most recent call last): 
    File "/usr/local/lib/python3.5/site-packages/requests/packages/urllib3/connectionpool.py", line 376, in _make_request 
    httplib_response = conn.getresponse(buffering=True) 
TypeError: getresponse() got an unexpected keyword argument 'buffering' 

During handling of the above exception, another exception occurred: 

Traceback (most recent call last): 
    File "/usr/local/lib/python3.5/site-packages/requests/packages/urllib3/connectionpool.py", line 559, in urlopen 
    body=body, headers=headers) 
    File "/usr/local/lib/python3.5/site-packages/requests/packages/urllib3/connectionpool.py", line 378, in _make_request 
    httplib_response = conn.getresponse() 
    File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/client.py", line 1174, in getresponse 
    response.begin() 
    File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/client.py", line 282, in begin 
    version, status, reason = self._read_status() 
    File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/client.py", line 243, in _read_status 
    line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1") 
    File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/python3.5/socket.py", line 571, in readinto 
    return self._sock.recv_into(b) 
    File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/python3.5/ssl.py", line 924, in recv_into 
    return self.read(nbytes, buffer) 
    File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/python3.5/ssl.py", line 786, in read 
    return self._sslobj.read(len, buffer) 
    File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/python3.5/ssl.py", line 570, in read 
    v = self._sslobj.read(len, buffer) 
ConnectionResetError: [Errno 54] Connection reset by peer 

During handling of the above exception, another exception occurred: 

Traceback (most recent call last): 
    File "/usr/local/lib/python3.5/site-packages/requests/adapters.py", line 376, in send 
    timeout=timeout 
    File "/usr/local/lib/python3.5/site-packages/requests/packages/urllib3/connectionpool.py", line 609, in urlopen 
    _stacktrace=sys.exc_info()[2]) 
    File "/usr/local/lib/python3.5/site-packages/requests/packages/urllib3/util/retry.py", line 247, in increment 
    raise six.reraise(type(error), error, _stacktrace) 
    File "/usr/local/lib/python3.5/site-packages/requests/packages/urllib3/packages/six.py", line 309, in reraise 
    raise value.with_traceback(tb) 
    File "/usr/local/lib/python3.5/site-packages/requests/packages/urllib3/connectionpool.py", line 559, in urlopen 
    body=body, headers=headers) 
    File "/usr/local/lib/python3.5/site-packages/requests/packages/urllib3/connectionpool.py", line 378, in _make_request 
    httplib_response = conn.getresponse() 
    File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/client.py", line 1174, in getresponse 
    response.begin() 
    File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/client.py", line 282, in begin 
    version, status, reason = self._read_status() 
    File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/client.py", line 243, in _read_status 
    line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1") 
    File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/python3.5/socket.py", line 571, in readinto 
    return self._sock.recv_into(b) 
    File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/python3.5/ssl.py", line 924, in recv_into 
    return self.read(nbytes, buffer) 
    File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/python3.5/ssl.py", line 786, in read 
    return self._sslobj.read(len, buffer) 
    File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/python3.5/ssl.py", line 570, in read 
    v = self._sslobj.read(len, buffer) 
requests.packages.urllib3.exceptions.ProtocolError: ('Connection aborted.', ConnectionResetError(54, 'Connection reset by peer')) 

During handling of the above exception, another exception occurred: 

Traceback (most recent call last): 
    File "/Users/laike9m/ICT/zhihu-analysis/dynamic/main.py", line 108, in <module> 
    main() 
    File "/Users/laike9m/ICT/zhihu-analysis/dynamic/main.py", line 89, in main 
    m.detect_new_question() 
    File "/Users/laike9m/ICT/zhihu-analysis/dynamic/monitor.py", line 32, in detect_new_question 
    question = latest_question = next(it) 
    File "/usr/local/lib/python3.5/site-packages/zhihu/topic.py", line 269, in questions 
    res = self._session.get(question_url, params=params) 
    File "/usr/local/lib/python3.5/site-packages/requests/sessions.py", line 480, in get 
    return self.request('GET', url, **kwargs) 
    File "/usr/local/lib/python3.5/site-packages/requests/sessions.py", line 468, in request 
    resp = self.send(prep, **send_kwargs) 
    File "/usr/local/lib/python3.5/site-packages/requests/sessions.py", line 576, in send 
    r = adapter.send(request, **kwargs) 
    File "/usr/local/lib/python3.5/site-packages/requests/adapters.py", line 426, in send 
    raise ConnectionError(err, request=request) 
requests.exceptions.ConnectionError: ('Connection aborted.', ConnectionResetError(54, 'Connection reset by peer')) 

Это очень распространенный вопрос: Python handling socket.error: [Errno 104] Connection reset by peer. У меня нет контроля над сервером, поэтому я не знаю, почему и как это происходит.

Сервер поддерживает поддержку, потому что я могу сделать сотни запросов (период длится час или больше).

+1

HTTP-соединения - * без гражданства *, поэтому даже с закрытием Keep-Alive является нормой. Вы запутались в истечении срока действия cookie с закрытыми соединениями? –

+0

Если вы используете «HTTP/2.x», которая является новой версией протокола HTTP, то, что говорит @MartijnPieters, верна. Но было бы интересно узнать, реализует ли Python «обновление» библиотеки запросов, чтобы лучше соответствовать «HTTP/2.x». – Torxed

+0

@Torxed: библиотека 'запросов' не поддерживает HTTP/2.x. Пока нет, во всяком случае. –

ответ

2

Либо сделайте свой B() синглтон, либо сделайте сессию атрибутом класса (и тем самым эффективно глобальным).

Например, что делает его атрибут класса только тогда, когда необходимо создать по крайней мере один экземпляр может выглядеть следующим образом:

class B: 
    def __init__(self): 
     if not hasattr(type(self), '_session'): 
      self._create_session() 

    @classmethod 
    def _create_session(cls): 
     cls._session = requests.Session() 

    def get(self): 
     self._session.get('some_url') 

При использовании сеанса может вызвать исключение, так как сервер не закрывает соединение сеанса правильно , просто заново создайте сеанс в это время:

def __init__(self): 
     if not hasattr(type(self), '_session'): 
      self._create_session() 

    @classmethod 
    def _create_session(cls): 
     cls._session = requests.Session() 

    def get(self): 
     retries = 5 
     while retries: 
      try: 
       return self._session.get('some_url') 
      except requests.ConnectionException as e: 
       last_connection_exception = e 
       retries -= 1 
     raise last_connection_exception 

Приведенный выше пример повторяет попытку до 5 раз. Вы делаете не необходимо каждый раз воссоздавать сеанс. Если соединение было закрыто, даже с исключением, объект сеанса просто создаст новое соединение TCP/IP для следующего запроса.

Если вы обнаружите, что объект сеанса каким-то образом снят и больше не способен создавать новые соединения, в то время как свежий сеанс действительно работает, тогда это будет ошибкой. Сообщите об этом проекту с подходящим MCVE.

+0

Да, я просто проверил на своем собственном сервере, что сеанс будет автоматически создан с помощью 'запросов' lib. Нет необходимости воссоздавать или даже беспокоиться о мониторинге неисправного трубопровода/сеанса. Однако я начинаю задаваться вопросом, какова фактическая проблема OP. – Torxed

+0

@Torxed Общая проблема: http://stackoverflow.com/questions/1434451/what-does-connection-reset-by-peer-mean. запросы не могут справиться с этим, но вызывают исключение. – laike9m

+0

@ laike9m Это то, что мы пытаемся вам рассказать. Сервер может не соблюдать «keep-alive» и, таким образом, отбрасывать сеанс TCP. Другими причинами этого могут быть сетевые спайки, wifi-соединение, являющееся неудовлетворительным или иным образом невосстановимым фатальными ошибками в сети. В любом случае, библиотека 'запросов' будет обрабатывать их, если нет, укажите свое фактическое сообщение об ошибке, а не то, что вы испытываете. – Torxed

Смежные вопросы