Requests: socket.error: [Errno 54] Conexão reiniciada pelo par

Criado em 22 set. 2011  ·  19Comentários  ·  Fonte: psf/requests

No momento, estou recebendo o erro socket.error: [Errno 54] Connection reset by peer quando uso requests.get(url, params=kwargs) e params contém grandes corpos de texto. Se eu truncar os dois grandes corpos de texto para menos de 2.900 caracteres cada, funcionará. Se eu executar o mesmo pedido get na linha de comando usando curl ele funcionará. Estou usando as solicitações da versão 0.6.1 que instalei usando pip install python-requests .

Não tenho certeza de como dizer a você para replicar o problema porque estou usando a biblioteca python-sendgrid para adicionar um boletim informativo à minha conta sendgrid e não quero postar meu nome de usuário e senha da API no ticket de problema. :)

Para testar na linha de comando usando curl, criei dois arquivos, cada um contendo texto simples e texto html, codificado por url usando um urlencoder . Então executei o seguinte comando.

export IDENTITY='<my identity number>'
export API_KEY='<my smtp password>'
export API_USER='<my smtp username>'
export NAME='<My Urlencoded Newsletter Name>'
export SUBJECT='<My Urlencoded Newsletter Subject>'
TEXT=`cat urlencoded.txt`; HTML=`cat urlencoded.html`; curl -d "api_user=$API_USER&api_key=$API_KEY&identity=$IDENTITY&name=$NAME&subject=$SUBJECT&text=$TEXT&html=$HTML" https://sendgrid.com/api/newsletter/newsletter/add.json

Comentários muito úteis

Doce ação! Mudar de requests.get(url, params=kwargs) para requests.post(url, data=kwargs) corrigiu isso! Desculpe incomodá-lo com isso e obrigado pela ajuda!

Todos 19 comentários

Hmm interessante. Se for esse o erro que está sendo gerado, tenho poucos motivos para acreditar que o servidor _não_ está realmente reiniciando a conexão.

Você tem um proxy HTTP como Charles disponível? Pode ajudar a lançar alguma luz sobre o que realmente está acontecendo.

Desculpe, esqueci de fornecer o traceback completo. Aqui está o traceback que recebo quando recebo o erro. Além disso, não estou entendendo como usar o proxy HTTP e por que isso faria diferença quando funciona a partir da linha de comando com curl.

Traceback (most recent call last):
  File "/Users/oconnor/.virtualenvs/emails/bin/django-admin.py", line 5, in <module>
    management.execute_from_command_line()
  File "/Users/oconnor/.virtualenvs/emails/lib/python2.7/site-packages/django/core/management/__init__.py", line 429, in execute_from_command_line
    utility.execute()
  File "/Users/oconnor/.virtualenvs/emails/lib/python2.7/site-packages/django/core/management/__init__.py", line 379, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/Users/oconnor/.virtualenvs/emails/lib/python2.7/site-packages/django/core/management/base.py", line 191, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/Users/oconnor/.virtualenvs/emails/lib/python2.7/site-packages/django/core/management/base.py", line 220, in execute
    output = self.handle(*args, **options)
  File "/Users/oconnor/Sites/wenworld/emails/emails/management/commands/ww_daily_headlines_send.py", line 114, in handle
    self.add_newsletter_to_sendgrid(sendgrid_newsletter_name, NEWSLETTER_SLUG)
  File "/Users/oconnor/Sites/wenworld/emails/emails/management/commands/ww_daily_headlines_send.py", line 94, in add_newsletter_to_sendgrid
    html=email.html
  File "/Users/oconnor/.virtualenvs/emails/src/sendgrid/src/sendgrid/__init__.py", line 67, in newsletter_add
    subject=subject, text=text, html=html)
  File "/Users/oconnor/.virtualenvs/emails/src/sendgrid/src/sendgrid/__init__.py", line 157, in get
    return self.call(method, **kwargs)
  File "/Users/oconnor/.virtualenvs/emails/src/sendgrid/src/sendgrid/__init__.py", line 56, in call
    result_json = json.loads(response.content)
  File "/Users/oconnor/.virtualenvs/emails/lib/python2.7/site-packages/requests/models.py", line 429, in __getattr__
    self._content = self.read()
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 351, in read
    data = self._sock.recv(rbufsize)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 553, in read
    s = self.fp.read(amt)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 1276, in read
    return s + self._file.read(amt - len(s))
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 380, in read
    data = self._sock.recv(left)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ssl.py", line 219, in recv
    return self.read(buflen)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ssl.py", line 138, in read
    return self._sslobj.read(len)
socket.error: [Errno 54] Connection reset by peer

A resposta que recebo do github é ...

<html>
<head><title>414 Request-URI Too Large</title></head>
<body bgcolor="white">
<center><h1>414 Request-URI Too Large</h1></center>
<hr><center>nginx/0.7.65</center>
</body>
</html>

O que é estranho porque, como mencionei antes, ele funciona com curl .

Se você reservar um tempo para examinar as duas solicitações de Charles (ou semelhante), tenho certeza de que verá o problema rapidamente.


Como diz o erro, o Request-URI é muito grande para o servidor processar, portanto, está interrompendo a conexão.

Com Requests, você está enviando todos os dados como uma string de consulta massiva no URI de Solicitação, conhecido como parâmetro GET. Ao usar curl, você está enviando dados codificados por formulário para o corpo da solicitação, conhecidos como dados POST.

Tentei usar requests.get(url, params=kwargs) e requests.post(url, params=kwargs) e ambos retornaram o mesmo erro. Por alguma razão, Charles não está capturando solicitações do curl e está apenas capturando solicitações do meu navegador e meu script de linha de comando python que usa python-requests.

Sem problemas.

params é para strings de consulta, data é para dados POST.

Doce ação! Mudar de requests.get(url, params=kwargs) para requests.post(url, data=kwargs) corrigiu isso! Desculpe incomodá-lo com isso e obrigado pela ajuda!

Não se preocupe :)

É estranho que receba o mesmo erro com dados semelhantes, a única diferença é que no meu caso não tenho uma lista grande ou tamanho de parâmetros. A mesma solicitação feita via CURL funciona bem, mas via solicitações me dá este erro.

request.exceptions.ConnectionError: HTTPSConnectionPool (host = 'sbarnea.com', port = 443): Máximo de tentativas excedido com url: / jira / rest / api / 2 / group? groupname = jira-administrators & expand = users (causado por: [Errno 54] Conexão reiniciada pelo par)

Ainda mais interessante, parece que a solicitação nem chega ao servidor web.

Alguma ideia do que isso poderia causar?

@ssbarnea Este problema tem mais de dois anos: não tem nada a ver com o problema que você está enfrentando atualmente. =) Você pode abrir uma nova edição para rastrear seu problema, por favor?

Melhor ainda, não abra um problema, vá falar com StackOverflow, você está fazendo uma pergunta e não tem nenhuma razão para acreditar que é um problema com o comportamento das solicitações. Faça um hash dos detalhes no StackOverflow e então podemos enviar um relatório de bug (se necessário).

É um comportamento muito estranho e tenho motivos para acreditar que não seja um bug nas solicitações, por isso abri um novo bug. Ainda estou investigando o que pode causar isso, só acontece na minha máquina, mas o mais interessante é que o CURL funciona (e os navegadores também). Obrigada.

Desculpe por manter isso aqui, mas descobri a causa disso:

#  resolver 127.0.0.1;
#  ssl_protocols TLSv1.2 TLSv1.1 ; # TLSv1
#  ssl_stapling on;
#  ssl_stapling_verify on;
#  ssl_session_cache builtin:1000;
#  ssl_session_timeout 30m;
#  ssl_ciphers HIGH:!RC4:!aNULL:!MD5;
#  ssl_prefer_server_ciphers on;

Ao desativar esses ajustes no servidor nginx, ele começou a trabalhar com solicitações, claramente uma delas está causando o mau funcionamento.

@ssbarnea
Provavelmente é um servidor bugado fazendo coisas erradas quando consultado em versões SSL / TLS específicas, conforme descrito em # 1567 (e vários outros).
Tente forçar uma versão diferente como explicada aqui (mais alguns parabéns para @Lukasa)

E o vencedor (perdedor) é ssl_protocols TLSv1.2 TLSv1.1;
Parece que remover TLSv1 dos protocolos suportados no servidor impede que as solicitações funcionem.

Agora, posso chamar isso de bug em solicitações ou uma biblioteca subjacente?

Nota: a remoção de TLSv1 é recomendada devido a questões de segurança, existem exploits com ele.

@ssbarnea Você descobrirá que a limitação não está em Requests, mas em Python. Atualmente, nenhuma versão enviada do Python tem suporte para qualquer versão do TLS mais recente do que V1.0, como você pode ver na tabela aqui .

Python 3.4 (ainda não enviado, sem garantias de que Requests seja compatível com ele) permite suporte para TLS1.2 e TLS1.1, então você pode tentar com isso. Caso contrário, você terá que permitir que o TLSv1 permita a passagem de solicitações.

Ainda tem uma coisa estranha: em ambos os casos usei Python, quando testei no OS X falhou, quando testei no Ubuntu funcionou.

Normalmente, eu não tocaria nas configurações padrão para SSL, mas gerei um relatório SSL e tentei resolver a maioria dos avisos:

FIPS requer: SSL v2 e SSL v3 estão desativados (apenas protocolos de versão TLS em uso)
Leia também sobre os ataques do BEAST.

Confira aqui:
https://sslcheck.globalsign.com/en_US/sslcheck/?host=sbarnea.com

Então, gostaria de saber se é possível corrigir isso, claramente se funciona com Python no Ubuntu, não pode ser específico para todas as versões de python.

Mm, infelizmente pode. Os recursos relativos do suporte ssl você obtém dependem da versão do OpenSSL que você instalou. Compare as duas versões. =)

Só para encerrar um pouco o assunto. Se o seu servidor web não permitir TLSv1, você obterá TLSv1.1 e 1.2 com python 2.7.9 (com lançamento previsto para dezembro de 2014). No entanto, você também pode instalar o PYOpenSSL e injetá-lo no urrlib3 (http://urllib3.readthedocs.org/en/latest/security.html#openssl-pyopenssl), que parece permitir o uso de solicitações para um servidor da web que desativou o TLSv1 com python 2.7.6 (e provavelmente outros).

import urllib3.contrib.pyopenssl
urllib3.contrib.pyopenssl.inject_into_urllib3()

Mas, realmente, o servidor da web provavelmente não deveria estar depreciando algo que força as pessoas a pularem por tantos obstáculos estranhos.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

avinassh picture avinassh  ·  4Comentários

mitar picture mitar  ·  4Comentários

NoahCardoza picture NoahCardoza  ·  4Comentários

xsren picture xsren  ·  3Comentários

cnicodeme picture cnicodeme  ·  3Comentários