使用 cURL 对 Cloudflare 进行问题排查

概述

cURL 是一个命令行工具,用于使用 URL 语法发送或接收 HTTP/HTTPS 请求。

此工具对问题排查非常有用:

  • HTTP/HTTPS 性能
  • HTTP 错误响应 
  • HTTP 头
  • API 接口
  • 对比服务器/代理的响应
  • SSL 证书

安装 cURL (Windows系统)

如果用于测试/问题排查的本地系统不是基于 Linux/UNIX 的系统,则 Windows 系统的命令行中可能不会默认安装 cURL。

curl.haxx.se 上的开源社区提供了一个适用于 Windows 用户的安装向导。如果使用此方法安装 cURL,请按照以下说明操作:

  1. 选择安装包类型:curl executable
  2. 选择平台:Windows / Win32Win64
  3. 选择渠道喜好:Generic
  4. 选择 Win32 版本(仅当您在步骤 2 中选择了 Windows / Win32 时):Unspecified

如果使用基于 x64 的系统,请参阅 curl.haxx.se 中的 64 位可执行文件

一般使用

发送标准 HTTP GET 请求的简单命令是:

curl -svo /dev/null http://example.com/

此命令将返回详细的 HTTP 响应和请求头,同时将body内容转储到本地空设备(它会立即丢弃写入其中的任何信息)。 

Trying 104.16.39.188...
* Connected to whiskytango.us (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: whiskytango.us
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date:Sat, 09 Jul 2016 11:53:37 GMT
< Content-Type: text/html
< Transfer-Encoding: chunked
< Connection: keep-alive
< Set-Cookie: __cfduid=d1f3639ea02e3abff666d; expires=Sun, 09-Jul-17 11:53:37 GMT; path=/; domain=.whiskytango.us; HttpOnly
< Cf-Railgun: direct (waiting for pending WAN connection)
< Last-Modified:Tue, 18 Aug 2015 09:05:34 GMT
< Server: cloudflare
< CF-RAY:2bfb939a0a57440e-SFO-DOG
<
{ [2291 bytes data]
* Connection #0 to host whiskytango.us left intact]]>

以上输出有助于确认 HTTP 响应,以及 Cloudflare 当前是否代理该站点的流量(在本例中,从 Server 和 CF-RAY 响应头可以明显看到)。

控制 cURL 输出

在某些情况下,您可能只需要查看某些特定的响应头值或部分信息,而无需查看整个 cURL 的输出/响应。

在这些情况下,cURL 可以与 grep/egrep 等命令结合使用,并使用 2>&1 导出至 stdout (标准输出):

curl -svo /dev/null http://whiskytango.us/img/sg50/IMG_0190.jpg 2>&1 | grep "CF-"
< CF-Cache-Status:HIT
< CF-RAY:2c07be0acb1d440e-SFO-DOG

在上面的示例中,此 cURL 用于输出  CF-Cache-Status 和 CF-RAY 响应头(是查看和排查缓存问题的有效方法)。

如果需要指定多个变量来解析 cURL 的标准输出,则可以使用 egrep

curl -svo /dev/null http://whiskytango.us/img/sg50/IMG_0190.jpg 2>&1 | egrep "Date|CF-|HTTP/"
> GET /img/sg50/IMG_0190.jpg HTTP/1.1
< HTTP/1.1 200 OK
< Date:Sun, 10 Jul 2016 23:35:54 GMT
< CF-Cache-Status:HIT
< CF-RAY:2c07d5b6bed7440e-SFO-DOG'

2>&1 结构表示stderr(标准错误)应该被重定向(并因此被包括在)stdout(标准输出)中。这有助于提供更详细的信息,并且能够将 cURL 输出到另一个命令进行解析(如 grep)。

常用参数

-svo /dev/null

此系列标志指定详细响应,同时将页面的输出/主体转储到 local /dev/null,此操作会立即丢弃该信息而不保存。这用于清晰显示信息,例如请求/响应头。以下是这些参数选项的详细说明:

  • -s: 静音模式。删除显示进度指示器或错误消息。
  • -v: 启用详细输出。 
  • -o /dev/null:将输出另存为文件。在此情况下,我们会将页面正文发送到 /dev/null。
--header "HEADER:VALUE"

上面的 --header 选项对于发送特定请求头非常有用,例如 Host、Set-Cookie,甚至是在特定的应用程序/平台中使用的自定义请求头。 

--user-agent "USERAGENTSTRING"

在某些情况下,Web 应用程序/服务器会设置规则阻拦 cURL 的默认user-agent字符串,因此从当前/已知浏览器发送合法的user-agent字符串会很有帮助。可能还存在需要针对特定 ​​UA 进行测试的情况。如果需要,可以在此处找到User-agent字符串的数据库。

--resolve hostname:port:DESTINATIONIPADDRESS http(s)://hostname/URL]]>

resolve 参数可设置特定主机和端口的自定义地址。这样可以使用指定地址发送 curl 请求,并不会使用正常解析的地址(修改 /etc/hosts 本地文件的替代方法)。此选项对于比较来自源站的服务器响应和 Cloudflare 代理的请求非常有用。

排查 HTTP 错误

在对 HTTP 错误进行排查时,尝试直接对源站发送 cURL 请求以确认响应,来跳过 Cloudflare 代理。

这可以通过两种方式实现,一是通过指定 Host 请求头并对源站的 IP 地址发送 cURL 请求,二是使用 --resolve 选项。 

curl -svo /dev/null --header "Host: example.com" http://123.123.123.123/
curl -svo /dev/null --resolve example.com:80:123.123.123.123 http://example.com/

下面是经过代理请求时出现 520 错误的例子:

curl -svo /dev/null http://whiskytango.us/
*   Trying 104.16.40.188...
* Connected to whiskytango.us (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: whiskytango.us
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 520 Unknown Origin-Error
< Date:Sun, 10 Jul 2016 19:55:33 GMT
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< Set-Cookie: __cfduid=d5a459e3960ee3254; expires=Mon, 10-Jul-17 19:55:18 GMT; path=/; domain=.whiskytango.us; HttpOnly
< Pragma: no-cache
< X-Frame-Options:SAMEORIGIN
< Server: cloudflare
< CF-RAY:2c069292c8e3440e-SFO-DOG
<
{ [3685 bytes data]
* Connection #0 to host whiskytango.us left intact]]>

对源站发送 cURL 显示发送的是空回复,这将可以确认 520 错误的根本原因:

curl -svo /dev/null --resolve whiskytango.us:80:123.123.123.123 http://whiskytango.us/
* Added whiskytango.us:80:123.123.123.123 to DNS cache
* Hostname whiskytango.us was found in DNS cache
*   Trying 123.123.123.123...
* Connected to whiskytango.us (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: whiskytango.us
> User-Agent: curl/7.43.0
> Accept: */*
>
* Empty reply from server
* Connection #0 to host whiskytango.us left intact]]>

性能问题排查

使用 cURL 可帮助衡量 HTTP/HTTPS 请求的延迟或性能下降。同时使用 cURL 和 time 命令是一种快速简便的方法:

time curl -svo /dev/null http://example.com/

此命令将显示完成请求所需的总时间:

* Trying 104.16.43.188...
* Connected to whiskytango.us (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: whiskytango.us
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date:Sun, 10 Jul 2016 19:10:28 GMT
< Content-Type: text/html
< Transfer-Encoding: chunked
< Connection: keep-alive
< Set-Cookie: __cfduid=de980d61f2dc09; expires=Mon, 10-Jul-17 19:10:28 GMT; path=/; domain=.whiskytango.us; HttpOnly
< Cf-Railgun: direct (waiting for pending WAN connection)
< Last-Modified:Tue, 18 Aug 2015 09:05:34 GMT
< Server: cloudflare
< CF-RAY:2c0650e4f76c4408-SFO-DOG
<
{ [925 bytes data]
* Connection #0 to host whiskytango.us left intact
real	0m0.079s
user	0m0.007s
sys	0m0.006s]]>

更全面和完整的性能测试方法是使用 -w 或 --write-out 参数选项,此参数可指定 cURL 在输出中打印的测试变量。通过在命令行上运行 man curl 或访问 curl.haxx.se 中的手册,可以找到此参数选项的完整变量列表。您可以在此文章中找到有关这些时间变量的进一步说明。

下面是使用 cURL 衡量请求中几个性能参数的运行示例:

curl -svo /dev/null https://example.com/ -w "\nContent Type: %{content_type} \
\nHTTP Code: %{http_code} \
\nHTTP Connect:%{http_connect} \
\nNumber Connects: %{num_connects} \
\nNumber Redirects: %{num_redirects} \
\nRedirect URL: %{redirect_url} \
\nSize Download: %{size_download} \
\nSize Upload: %{size_upload} \
\nSSL Verify: %{ssl_verify_result} \
\nTime Handshake: %{time_appconnect} \
\nTime Connect: %{time_connect} \
\nName Lookup Time: %{time_namelookup} \
\nTime Pretransfer: %{time_pretransfer} \
\nTime Redirect: %{time_redirect} \
\nTime Start Transfer: %{time_starttransfer} \
\nTime Total: %{time_total} \
\nEffective URL: %{url_effective}\n" 2>&1

cURL 输出之后,将显示变量值。以下是上例中的 cURL的输出结果示例:

 > GET / HTTP/1.1
> Host: whiskytango.us
> User-Agent: curl/7.43.0
> Accept: */*
>
{ [5 bytes data]
< HTTP/1.1 200 OK
< Date:Sun, 10 Jul 2016 19:25:06 GMT
< Content-Type: text/html
< Transfer-Encoding: chunked
< Connection: keep-alive
< Set-Cookie: __cfduid=dcfcff083c6e553dc6750134395b8bf711468178706; expires=Mon, 10-Jul-17 19:25:06 GMT; path=/; domain=.whiskytango.us; HttpOnly
< Cf-Railgun: direct (starting new WAN connection)
< Last-Modified:Tue, 18 Aug 2015 09:05:34 GMT
< Server: cloudflare
< CF-RAY:2c0666564631440e-SFO-DOG
<
{ [935 bytes data]
* Connection #0 to host whiskytango.us left intact
Content Type: text/html
HTTP Code:200
HTTP Connect:000
Number Connects:1
Number Redirects:0
Redirect URL:
Size Download:14166
Size Upload:0
SSL Verify:0
Time Handshake:0.076
Time Connect:0.018
Name Lookup Time:0.002
Time Pretransfer:0.076
Time Redirect:0.000
Time Start Transfer:0.111
Time Total:0.129
Effective URL: https://whiskytango.us/

从输出中,可以查看可能会影响加载时间的有用性能信息,例如 TLS 握手、DNS 查找时间、重定向、传输、上传/下载大小等。 

使用 -w--write-out 时,可以通过在每个变量前面用 \n 添加新行来实现更清晰的结果输出。这将在新行上打印每个变量,而不是在一行中显示所有指标。

缓存

在查看 HTTP 响应头时,cURL 还有助于查看缓存行为。在使用 Cloudflare 对缓存进行问题排查时,几乎总是考虑以下 HTTP 响应头:

  • CF-Cache-Status
  • Cache-control/Pragma
  • Expires
  • Last-Modified
  • S-Maxage

有关 Cloudflare 缓存的详细信息,请参阅以下文章:如何将我想速缓存的内容告知 Cloudflare?

使用 cURL 时,使用本文排查 HTTP 错误部分中所述的方法有助于比较来自源站的控制缓存信息的响应头,以及 Cloudflare 代理请求时的响应头。

下面的示例控制输出来显示源站的同一文件的三个不同版本(注意 Last-Modified 头),并确认间歇地为请求提供过时缓存的原因:

curl -vso /dev/null -H "Host: example.com" http://162.242.199.20/courses 2>&1 | egrep "< Date|< Last-Modified|< ETag"
< Last-Modified:Sun, 23 Mar 2014 01:07:13 GMT
< ETag:"4147-4f53bbd33b240"
< Date:Thu, 03 Apr 2014 22:52:58 GMT

curl -vso /dev/null -H "Host: example.com" http://162.242.199.20/courses 2>&1 | egrep "< Date|< Last-Modified|< ETag"
< Last-Modified:Sun, 23 Mar 2014 01:07:26 GMT
< ETag:"4149-4f53bbdfa0f80"
< Date:Thu, 03 Apr 2014 22:53:00 GMT

curl -vso /dev/null -H "Host: example.com" http://162.242.199.20/courses 2>&1 | egrep "< Date|< Last-Modified|< ETag"
< Last-Modified:Sun, 23 Mar 2014 01:03:02 GMT
< ETag:"413d-4f53bae3dbd80"
< Date:Thu, 03 Apr 2014 22:53:43 GMT

排查 SSL/TLS

使用 cURL 查看证书

除了使用 openSSL 查看站点的证书信息和进行问题排查之外,cURL 是另一种可用于查看 HTTPS 请求中提供的证书的工具:

curl -svo /dev/null https://whiskytango.us/ 2>&1 | egrep -v "^{.*$|^}.*$|^\* http.*$"

使用上面的命令,输出结果将显示许多有用的信息,例如为请求返回的 TLS 握手和证书信息(在这种例子中,这个代理请求使用 Comodo 颁发的共享证书):

*  Trying 104.16.43.188...
* Connected to whiskytango.us (104.16.43.188) port 443 (#0)
* ALPN, offering http/1.1
* Cipher selection:ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /usr/local/etc/openssl/cert.pem
  CApath: none
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-ECDSA-AES128-GCM-SHA256
* ALPN, server accepted to use http/1.1
* Server certificate:
* 	 subject:OU=Domain Control Validated; OU=PositiveSSL Multi-Domain; CN=ssl329925.cloudflaressl.com
* 	 start date:2016-01-04 00:00:00 GMT
* 	 expire date:2016-12-31 23:59:59 GMT
* 	 subjectAltName: whiskytango.us matched
* 	 issuer:C=GB; ST=Greater Manchester; L=Salford; O=COMODO CA Limited; CN=COMODO ECC Domain Validation Secure Server CA 2
* 	 SSL certificate verify ok.
> GET / HTTP/1.1
> Host: whiskytango.us
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date:Sun, 10 Jul 2016 21:41:04 GMT
< Content-Type: text/html
< Transfer-Encoding: chunked
< Connection: keep-alive
< Set-Cookie: __cfduid=dde6e686bb3fffe36d57863a78828beb11468186864; expires=Mon, 10-Jul-17 21:41:04 GMT; path=/; domain=.whiskytango.us; HttpOnly
< Cf-Railgun: direct (starting new WAN connection)
< Last-Modified:Tue, 18 Aug 2015 09:05:34 GMT
< Server: cloudflare
< CF-RAY:2c072d7e8be6440e-SFO-DOG
<
* Connection #0 to host whiskytango.us left intact

字符串 2>&1 | egrep -v "^{.*$|^}.*$|^\* http.*$" 可用于解析 cURL 输出,以便更清晰地显示 TLS 握手/证书信息。

通过使用 --resolve 标志可以查看源站安装的证书(假设已安装):

curl -svo /dev/null --resolve www.example.com:443:ORIGINIPHERE https://www.example.com/

测试 TLS 版本

您可能需要针对特定 TLS 版本进行测试(在针对旧版浏览器排查问题时,或确认源站支持的 TLS版本时)。 

以下是使用特定TLS协议版本发送请求的参数:

  • --tlsv1.0
  • --tlsv1.1
  • --tlsv1.2
  • --tlsv1.3

以下是使用 TLS 协议版本 1.2 发送 HTTPS 请求的示例 cURL:

curl -svo /dev/null --tlsv1.1 https://whiskytango.us/ 2>&1 | egrep -v "^{.*$|^}.*$|^\* http.*$"
*   Trying 104.16.40.188...
* Connected to whiskytango.us (104.16.40.188) port 443 (#0)
* ALPN, offering http/1.1
* Cipher selection:ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /usr/local/etc/openssl/cert.pem
  CApath: none
* TLSv1.1 (OUT), TLS header, Certificate Status (22):
* TLSv1.1 (OUT), TLS handshake, Client hello (1):
* TLSv1.1 (IN), TLS handshake, Server hello (2):
* TLSv1.1 (IN), TLS handshake, Certificate (11):
* TLSv1.1 (IN), TLS handshake, Server key exchange (12):
* TLSv1.1 (IN), TLS handshake, Server finished (14):
* TLSv1.1 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.1 (OUT), TLS change cipher, Client hello (1):
* TLSv1.1 (OUT), TLS handshake, Finished (20):
* TLSv1.1 (IN), TLS change cipher, Client hello (1):
* TLSv1.1 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.1 / ECDHE-RSA-AES128-SHA
* ALPN, server accepted to use http/1.1
* Server certificate:
* 	 subject:OU=Domain Control Validated; OU=PositiveSSL Multi-Domain; CN=ssl329924.cloudflaressl.com
* 	 start date:2016-01-03 00:00:00 GMT
* 	 expire date:2016-12-31 23:59:59 GMT
* 	 subjectAltName: whiskytango.us matched
* 	 issuer:C=GB; ST=Greater Manchester; L=Salford; O=COMODO CA Limited; CN=COMODO RSA Domain Validation Secure Server CA 2
* 	 SSL certificate verify ok.
> GET / HTTP/1.1
> Host: whiskytango.us
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date:Mon, 18 Jul 2016 20:48:41 GMT
< Content-Type: text/html
< Transfer-Encoding: chunked
< Connection: keep-alive
< Set-Cookie: __cfduid=dfdfe3bd6aec2927ab36d3748cd6a30a31468874921; expires=Tue, 18-Jul-17 20:48:41 GMT; path=/; domain=.whiskytango.us; HttpOnly
< Cf-Railgun: direct (starting new WAN connection)
< Last-Modified:Tue, 18 Aug 2015 09:05:34 GMT
< Server: cloudflare
< CF-RAY:2c48cbc21031440e-SFO-DOG
<
* Connection #0 to host whiskytango.us left intact

参考

curl.haxx.se

Not finding what you need?

95% of questions can be answered using the search tool. This is the quickest way to get a response.

由 Zendesk 提供技术支持