所以我花了大约一周的时间试图解决这个问题。以下是概要:
我在 PHP 中使用 CURL 从 API 中提取数据。随着对 API 调用的响应越来越大(一次提取超过 15k 条记录),我注意到任何需要 5 分钟或更长时间(几秒钟内)的 API 调用都无法在我的 CentOS 和 Suse 服务器上返回。因此,我通过 CURL 从 CLI 测试了 API 调用,但遇到了同样的问题。奇怪的是,如果我通过 OS X 运行 CURL 命令,该命令运行良好并在大约 7 分钟后返回。
下面是我通过 CURL 运行的命令(creds censored):
curl -m 0 -k --trace-ascii trace.txt --trace-time -X GET -H "tenant-code: 1cmPx7tqVDVTdN1GSelwycFUmICmASnLCmNQsV72" -H "Authorization: Basic JxHAsXeUiHMRkS8Msiu6pWb3PvY20p6am3QvXCY3knXTAntlxTBS3EyEDgly" -H "Content-Type: application/json" -H "Cache-Control: no-cache" 'https://api.endpoint.com/API/v1/system/users/search?groupid=555' > dump.txt
以下是 CURL 针对各个平台的版本输出:
CentOS(这是我真正需要它工作的地方)-
curl 7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.19.1 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2
Protocols: tftp ftp telnet dict ldap ldaps http file https ftps scp sftp
Features: GSS-Negotiate IDN IPv6 Largefile NTLM SSL libz
Suse-
curl 7.19.7 (x86_64-suse-linux-gnu) libcurl/7.19.7 OpenSSL/0.9.8j zlib/1.2.7 libidn/1.10
Protocols: tftp ftp telnet dict ldap ldaps http file https ftps
Features: GSS-Negotiate IDN IPv6 Largefile NTLM SSL libz
OS X-
curl 7.37.1 (x86_64-apple-darwin14.0) libcurl/7.37.1 SecureTransport zlib/1.2.5
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smtp smtps telnet tftp
Features: AsynchDNS GSS-Negotiate IPv6 Largefile NTLM NTLM_WB SSL libz
这些是我从 Centos 获取的错误代码:
curl: (56) SSL read: errno -5961
我找不到文档中引用的代码。 https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/SSL_functions/sslerr.html
我得到了与 Suse 稍有不同的错误:
curl: (52) SSL read: error:00000000:lib(0):func(0):reason(0), errno 104
错误 104 让我相信服务器正在停止/重置连接,但服务器端日志并未显示连接被断开,OS X 可以毫无问题地提取数据。我甚至尝试欺骗用户代理以确保这不是问题所在。
因此,此时我假设 SSL 包 SecureTransport 正在执行 OpenSSL 和 NSS 没有执行的操作。问题是,这是什么操作?如果不是,问题是什么?
答案1
在 MacOSX 机器上运行 curl 命令,但不要重定向输出,让它流到您的 shell 窗口。观察是否似乎涉及任何缓冲,即,您是否从一开始就得到输出,一次一点,还是在 5 分钟内什么都没有得到,然后一下子得到大量数据?
在超时的机器上再次运行 curl 命令,并比较行为。如果您的输出被 API 服务器上的某些后台进程缓冲,则您可能在它完成查询之前无法获得结果。您的客户端应用程序、客户端操作系统、服务器操作系统、服务器的 REST API 以及它们之间的 SSL 之间的某些东西可能具有非零的超时值,并且如果该计时器在 5 分钟内没有看到任何数据流动,它可能会关闭您的连接而不说明原因。我看到这种情况在基于 HTTP 的服务中经常发生。在 perl 中,我习惯性地将一个放在$|=1;
代码顶部以禁用服务器端的输出缓冲。
第三方设备(例如 Cisco ASA)也可能存在 NAT 规则超时和触发问题。我在尝试从 ASA 外部的客户端读取 AMANDA 备份时遇到了这个问题。如果客户端花费太长时间通过 ASA 将其大小估计值返回到 AMANDA 服务器,ASA 将放弃其动态 NAT 规则,备份将失败。如果正常运行的 MacOSX 在它和 API 服务器之间没有防火墙,而出现故障的 MacOSX 有防火墙,则此建议值得研究。
如果 MacOSX 的超时值设置为 0(永远等待),而 Linux 默认的超时限制为 60 或 90 秒,我一点也不会感到惊讶。