【解决】调第三方https接口概率性报cURL error 28: NSS: client certificate not found (nickname not specified)错误

错误场景描述

使用guzzle的curl方法,连接第三方https接口,概率性出现 cURL error 28: NSS: client certificate not found (nickname not specified) 报错,查看phpinfo发现curl的ssl_version为nss。另,该https接口不需要证书认证,且接口数据较大。

错误查找

一般找错都是根据错误信息进行查找,于是我就根据

cURL error 28: NSS: client certificate not found (nickname not specified),error code 为 0

这个错误信息搜了很多文章并仔细比对情况,如:
https://stackoverflow.com/questions/15773806/nss-client-certificate-not-found-nickname-not-specified

https://stackoverflow.com/questions/19265100/curl-command-unable-to-load-client-cert-8018/20140138#20140138

总结起来就是将nss更换为openssl,但仔细看又发现,跟环境相关的话应该这个错误应该是必现的而不是概率性的。根据经验,概率性报错可能有两种情况:

  1. 网络不稳定。(第三方接口是香港那边的,可能会被墙)
  2. 超时。

遂再根据这两个条件继续排查,查看日志发现在某一时间出现报错,咨询第三方接口提供者发现,这个时间并没有我ip的访问记录,也就是说请求没有发送成功。再仔细研究日志发现,从开始发送请求到抛出错误信息,日志相隔时间为90s,巧的是我设置的超时时间也是90s,但是之前超时是会明确抛出超时错误的。。

为了验证这个想法,我将超时时间设置成1s,调用接口,果然又报cURL error 28: NSS: client certificate not found (nickname not specified)错误,并且复现率极高。至此,问题就找到了,就是超时

错误解决

但是超时为什么不抛超时异常而抛出cURL error 28: NSS: client certificate not found (nickname not specified)这个错误呢?
在命令行使用curl命令请求该https接口,结果如下:(-k表示跳过证书认证)

curl -k https://xxx.com -vvv
* About to connect() to xxx.com port 443 (#0)
* Trying …..
* Connected to xxx.com (…) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* NSS: client certificate not found (nickname not specified)
* SSL connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate:
* subject: CN=*.xxx.com,O=Noble Apex Advisors Limited,L=North Point,C=HK
* start date: Jan 16 00:00:00 2018 GMT
* expire date: Oct 02 12:00:00 2020 GMT
* common name: *.xxx.com
* issuer: CN=DigiCert SHA2 Secure Server CA,O=DigiCert Inc,C=US
GET xxx.com HTTP/1.1
User-Agent: curl/7.29.0
Host: xxx.com
Accept: /

< HTTP/1.1 200 OK
< Server: openresty/1.13.6.1
< Date: Tue, 19 Jun 2018 03:47:14 GMT
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< Age: 3442
< Cache-Control: max-age=7808
< Vary: Origin
< Vary: Origin

发现有一个很眼熟的信息:

NSS: client certificate not found (nickname not specified)

也就是说,每次连接都会有这个信息,并且是在一开始连接时就有。
那为什么之前会报超时而不报nss错误呢?—-因为之前这个第三方接口用的是http协议,本来就不需要证书认证的,之后改成https协议之后,这个接口仍然不需要证书认证,所以verify设置为false,跳过证书认证(加上证书会有一堆问题,这个暂时没有深究为什么)。

那为什么超时的错误会被nss错误覆盖呢?
https://github.com/dpull/lua-webclient/issues/7

参照大佬的issue发现,nss这个错误是一个可以被忽略的notice,并不会影响后续执行。但是由于这个notice出现时间早,所以覆盖掉了真正的错误原因。

总结

跟第三方的后续深入沟通时发现,此接口的建议连接时间为5分钟,而我先入为主设置了90s,所以就经常会有超时现象发生。这个故事也告诉我们,开发过程中沟通!沟通!真的是一个很重要的过程。

在解决概率性bug(因为复现比较困难)时,日志真的非常非常重要的,日志记录的错误信息、日志时间,这些都是我们分析问题,解决问题的工具。

你可能感兴趣的:(经验之谈)