有个用 Requests 的脚本,访问 https://dictation.nuancemobility.net 这个 URL 。但是奇怪的是在 CentOS 可以正常工作,从服务器获得 200 响应,放到 Debian/Ubuntu 上就只能从服务器获得 500 响应。
这个代码如下:
<pre><code>
class Nuance_api():
def __init__(self, appid, appkey, n_id):
self.appid = appid
self.appkey = appkey
self.id = n_id
def recogenize(self, language, voicefile):
nuance_url = 'https://dictation.nuancemobility.net/NMDPAsrCmdServlet/dictation'
n_params = {'appId':self.appid, 'appKey':self.appkey, 'id':self.id}
voice_file = {'file': open(voicefile, 'rb')}
n_headers = {'Accept-Language':language, 'Content-Type':'audio/amr;codec=amr;bit=4.75;rate=8000', 'Accept':'text/plain', 'Accept-Topic':'Dictation'}
r = requests.post(url=nuance_url, params=n_params, headers=n_headers, files=voice_file, verify=False)
if r.status_code == 200 :
return r.text
</code></pre>
由于涉及到隐私的 key 等信息,单用这段代码测试比较麻烦。可以说明的是,这段代码在 CentOS 没有任何问题,可以返回识别的 text.
那么,事情就集中到: Debian/Ubuntu 上的 requests 为什么就不能像 CentOS 一样工作?
经过一些 debug ,这个服务器使用 TLS v1.2 或 v1 来进行握手,那么我甚至将代码改写为强制使用 TLS v1.2 ,在 Debian/Ubuntu 上同样失败。抓包显示,握手后服务端连续发来 4 个 hello ,但是在 CentOS 上的抓包显示为握手后就开始传输数据了。这表明握手并不成功(至少我这么认为)。
有些文章说 Debian/Ubuntu 上的 openssl 默认不设定任何 CA bundle ,但是 Requests 使用的是自己的 CA bundle ,为了测试,特意在代码中将 verify='我的 cacert.pem',当我的 cacert.pem 里没有任何 root certificate 的时候,确实是 ssl verify failure ,加上该网站证书链里的顶级 VeriSign Class 3 证书,就可以通过验证。所以, CA bundle 不是症结。
那么,究竟为什么。到底 Debian/Ubuntu 上使用 Requests 的正确姿势是什么呢?
盼望这里有大神有些许经验。 Stackoverflow, GitHub 在这个问题上都阵亡了。满世界都是 ssl 验证不通过的问题,但是能有效解决的很少。涉及 requests ,那就更少了。
1
msg7086 2015-09-30 22:50:41 +08:00 1
握手失败的时候竟然能从服务器那边获取到 500 错误?手握在什么东西上了?
|
2
pc10201 2015-09-30 22:56:35 +08:00
|
3
zjxubinbin 2015-09-30 23:02:29 +08:00
@msg7086 应该是握在蛋上面了~
|
4
alexapollo 2015-09-30 23:05:52 +08:00
pip install pyopenssl ndg-httpsclient pyasn1
可以试试 |
5
187j3x1 2015-09-30 23:09:01 +08:00
这跟放一段伪代码有什么区别
|
6
mengzhuo 2015-09-30 23:14:51 +08:00 via iPhone 1
ca 库地址设置
python 编译时的 openssl 版本 |
7
ryd994 2015-09-30 23:31:06 +08:00 via Android 1
|
8
Strikeactor 2015-09-30 23:37:21 +08:00 1
@msg7086 JB 上
逃( |
9
adrianzhang OP @msg7086 说的有道理。那请教一下这个握手之后,服务器为什么会发过来 4 个 hello ?一定有什么不同寻常的事情发生了。
@pc10201 关闭了也不行,代码里可以看到 verify=False 的。这是最初的代码,不通过后才想尽办法加 ca 等,开启验证找问题的。 @alexapollo 谢谢。我去试试看。 @187j3x1 你说咋办?把 id 和 key 都放上来?这个代码很特殊在于有一定的 headers 和 parameters ,以及传输文件,如果用别的网站做演示的话,没法复现错误啊。 @mengzhuo Requests 使用的是自己带的 CA bundle ,在 /usr/local/lib/python2.7/site-packages/requests/cacert.pem 。用 verify=开关设置为自己定的 pem ,这个实验在问题中提到了。 python 和 openssl 版本是这样的: 1) 从 ISO 安装的 ElementoryOS Luna (基于 Ubuntu 12.02 ) 2) 或 Freya(基于 Ubuntu 14.04 TLS) 3) 官方 Docker python 2.7.10 镜像(基于 Debian) 这三个环境都是从 ISO 安装后未作任何特殊设置。因此 python 以及 openssl 版本等信息可以从这些环境里得到。比如直接 run 一个 docker python 2.7.0 。请看下 CentOS, python 2.6.6, OpenSSL 1.0.1e-fips 11 Feb 2013 。 刚才又做了个测试,在 Debian/Ubuntu 上,使用 curl 是成功的,问题一定出在 python, openssl, requests 这几个中间。 |
10
adrianzhang OP @ryd994 如果使用 https://www.google.com ,是没有任何问题的。这个特殊情况只出现在这个特殊场景下。
|
11
adrianzhang OP @alexapollo 仍然无法获取正确响应。
|
12
adrianzhang OP |
13
binux 2015-10-01 00:04:57 +08:00
UA
|
14
binux 2015-10-01 00:11:22 +08:00 1
requests 版本差异没见提到
|
15
azurefang 2015-10-01 00:18:35 +08:00
楼主你试着装一下 python2.7.9
|
16
alexapollo 2015-10-01 00:22:53 +08:00
https://dictation.nuancemobility.net/ 怎么普通的点进去都是 500 。。而且你没看 500 的完整回复吗?
我猜是有什么特殊的配置写在代码里了。 |
17
adrianzhang OP @binux UA 应该不是问题,因为同样的代码在 CentOS 上是 work 的。 requests 在 debian 里是 requests==2.7.0
在 centos 上是 requests==1.2.3 @azurefang 谢谢,我一会儿测试下 2.7.9 @alexapollo 是的,代码没有给出必要的 credentials ,因为涉及隐私内容没法放到公共空间里,这个完整 URL 是有 headers, parameters, file, 请看代码。有空我去申请个测试的帐号。 感谢各位,现在联系到了 Requests 的作者,正在跟他沟通做 debug 。如果各位还有什么需要我提供的也请继续回复,我会持续 post. |
18
binux 2015-10-01 00:45:43 +08:00 2
@adrianzhang requests 默认 UA 会带上系统信息的, 而且你这个版本差太多了啊!
|
19
adrianzhang OP @binux 谢谢了!还真是版本差异产生的,见题目上我的补充。
|
20
dingyaguang117 2015-10-01 06:31:10 +08:00 via iPhone
没有用 requirements 并且固定版本号的习惯呀。。。
之前同样的代码, python 版本不一样也会有问题。。。 |
21
adrianzhang OP @dingyaguang117 说起来一肚子苦水。
事情原本是这样的:标的环境是那个 Debian ,固定版本号的各种组件。在这个环境里写的脚本不 work 。为了找原因,用替换法,换个环境,结果就恰巧换到了那个 CentOS 。而脚本在 CentOS 上 work ,把我引入歧途,误以为问题出在 Debian 的某些配置上,既不是 Nuance 方面的问题也不是脚本的问题。所以一直纠结在 Debian 环境的排错上,所以才一周时间都徘徊在死胡同里。 跟作者沟通,他也直说了,即使是老版本,也需要用 data 对象,至于为什么 CentOS 上能工作,这对他来说也是一个谜。可能会涉及到更底层的一些东西,比如 python 的处理或者 Linux 本身的处理。这个没有时间去具体分析,等项目结束有空的时候,再去深挖一下到底是什么情况。太罕见了。 |