urlfetch.UrlfetchException: _ssl.c:510: EOF 发生违反协议

urlfetch.UrlfetchException: _ssl.c:510: EOF occurred in violation of protocol

我在 ubuntu

上使用 python 2.7.6

当我使用 urlfetch (1.0.2) 到 post 数据到远程服务器时出现此错误。 2天前服务器ssl证书更新后开始

类似的问题已报告给另一个 python 软件包 request。解决方案是通过 运行

更新一些依赖
pip install --force-reinstall requests[security]

但我只得到了这个

Requirement already satisfied: requests[security] in /usr/lib/python2.7/dist-packages
  requests 2.2.1 does not provide the extra 'security'

似乎没有下载和安装任何内容。

一些post建议它与密码有关(https://github.com/kennethreitz/requests/issues/3608#issuecomment-250681069)

openssl s_client -connect www.example.com:443 
CONNECTED(00000003)
140353237063328:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:177:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 305 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
---

看起来正常吗?我能做些什么来修复它吗?

目标服务器在 Google App Engine 上。新的 SSL 证书不支持 vip.

Ubuntu 版本信息:

NAME="Ubuntu"
VERSION="14.04.2 LTS, Trusty Tahr"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 14.04.2 LTS"
VERSION_ID="14.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"

我的第一选择是使用 this answer 通过猴子补丁 ssl.py 解决问题。

import ssl
from functools import wraps
def sslwrap(func):
    @wraps(func)
    def bar(*args, **kw):
        kw['ssl_version'] = ssl.PROTOCOL_TLSv1
        return func(*args, **kw)
    return bar

ssl.wrap_socket = sslwrap(ssl.wrap_socket)

但是没有用。

最后我发现我可以通过从源代码升级 python 到 2.7.13 来解决它。以下是步骤:

1) 安装python 开发依赖

sudo apt-get install -y \
autotools-dev      \
blt-dev            \
bzip2              \
dpkg-dev           \
g++-multilib       \
gcc-multilib       \
libbluetooth-dev   \
libbz2-dev         \
libexpat1-dev      \
libffi-dev         \
libffi6            \
libffi6-dbg        \
libgdbm-dev        \
libgpm2            \
libncursesw5-dev   \
libreadline-dev    \
libsqlite3-dev     \
libssl-dev         \
libtinfo-dev       \
mime-support       \
net-tools          \
netbase            \
python-crypto      \
python-mox3        \
python-pil         \
python-ply         \
quilt              \
tk-dev             \
zlib1g-dev

2) 下载源码

wget https://www.python.org/ftp/python/2.7.13/Python-2.7.13.tgz

3) 解压

tar xfz Python-2.7.13.tgz

4) 配置

cd Python-2.7.13/
./configure --prefix /usr/local/lib/python2.7.13 --enable-ipv6

5) 构建

make

6) 部署

sudo make install

7) 安装pipurlfetch以及其他依赖项

此错误发生在不支持 TLS SNI(服务器名称指示)扩展的旧版本 Python 上。您需要使用 SNI 通过 HTTPS 连接到 App Engine 上托管的站点。 Python 2.7.9 及更高版本似乎支持 SNI。

如果您 一个用Python 编写的App Engine 应用发出请求并且需要SNI 支持,您需要reference version 2.7.11 of the ssl library in your app.yaml file 否则您将运行 进入同一问题。