有次在使用Python(使用自帶的urllib2庫(kù))去調(diào)用一個(gè)HTTPS的API時(shí)一直報(bào)錯(cuò)error 54, 'Connection reset by peer; 但是通過(guò)postman等工具的時(shí)候卻能正常返回結(jié)果:
import urllib2
r = urllib2.urlopen('https://xxxxx')
print r.read()
異常如下:
raise URLError(err)
urllib2.URLError: <urlopen error [Errno 54] Connection reset by peer>
通過(guò)查看urllib2的源碼發(fā)現(xiàn), urllib2是httplib模塊的一個(gè)更高層的封裝,httplib是python中一個(gè)相對(duì)底層的http請(qǐng)求模塊,httplib請(qǐng)求流程如下, HTTPConnect()通過(guò)python的socket模塊發(fā)起請(qǐng)求;
(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
當(dāng)發(fā)起HTTPS請(qǐng)求,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.
這個(gè)模塊依賴計(jì)算機(jī)上的openssl庫(kù); 不同版本的openssl可能會(huì)導(dǎo)致行為的一些變化;
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 是一個(gè)開源的安全套接字層密碼庫(kù),囊括主要的密碼算法、常用的密鑰和證書封裝管理功能及SSL協(xié)議;
問(wèn)題原因: 本地MAC環(huán)境的openssl版本位0.9.8zh, 0.9.8zh版本不支持TLSV1.1 TLSV1.2(出于安全考慮,這次被調(diào)用的HTTPS已經(jīng)不支持TLSV1.1以下的版本了)
$openssl version
OpenSSL 0.9.8zh 14 Jan 2016
解決方法: 升級(jí)本地的openssl>=1.0.1