有次在使用Python(使用自带的urllib2
库)去调用一个HTTPS的API时一直报错error 54, 'Connection reset by peer
; 但是通过postman等工具的时候却能正常返回结果:
import urllib2
r = urllib2.urlopen('https://xxxxx')
print r.read()
异常如下:
raise URLError(err)
urllib2.URLError: <urlopen error [Errno 54] Connection reset by peer>
通过查看urllib2
的源码发现, urllib2
是httplib
模块的一个更高层的封装,httplib
是python中一个相对底层的http请求模块,httplib
请求流程如下, HTTPConnect()
通过python的socket模块发起请求;
(null)
|
| HTTPConnection()
v
Idle
|
| putrequest()
v
Request-started
|
| ( putheader() )* endheaders()
v
Request-sent
|
| response = getresponse()
v
Unread-response [Response-headers-read]
|\____________________
| |
| response.read() | putrequest()
v v
Idle Req-started-unread-response
______/|
/ |
response.read() | | ( putheader() )* endheaders()
v v
Request-started Req-sent-unread-response
|
| response.read()
v
Request-sent
当发起HTTPS请求,socket就变成了SSLSocket
(TLS/SSL wrapper for socket objects, 继承于socket.socket); 查看官方文档:
This module uses the OpenSSL library. It is available on all modern Unix systems, Windows, Mac OS X, and probably additional platforms, as long as OpenSSL is installed on that platform.
这个模块依赖计算机上的openssl库; 不同版本的openssl可能会导致行为的一些变化;
Note: Some behavior may be platform dependent, since calls are made to the operating system socket APIs. The installed version of OpenSSL may also cause variations in behavior. For example, TLSv1.1 and TLSv1.2 come with openssl version 1.0.1.
OpenSSL 是一个开源的安全套接字层密码库,囊括主要的密码算法、常用的密钥和证书封装管理功能及SSL协议;
问题原因: 本地MAC环境的openssl版本位0.9.8zh, 0.9.8zh版本不支持TLSV1.1 TLSV1.2(出于安全考虑,这次被调用的HTTPS已经不支持TLSV1.1以下的版本了)
$openssl version
OpenSSL 0.9.8zh 14 Jan 2016
解决方法: 升级本地的openssl>=1.0.1