當我們訪問一個網站或者網站接口服務,想知道"時間都去哪里了",這時候我們借助工具來分析。
可以將時間大致分為兩部分:一部分是從我們請求到網站服務端所經歷的耗時,另一部分是服務端自身處理該服務完畢后響應回來的時間,這些都是可以作為后面結果分析的判斷依據。
下面將介紹兩個方案,僅供參考。
開始計時
使用系統curl命令模擬網站服務請求,得到各個時間段的時間。
需要注意的是:請確保curl 是最新版本,否則一些參數選項無法使用。
例子:
$ curl -w "Result: \n dnslookup: %{time_namelookup} \n connect: %{time_connect} \n appconnect: %{time_appconnect} \n pretransfer: %{time_pretransfer} \n starttransfer: %{time_starttransfer} \n total: %{time_total} \n ----\n time_redirect: %{time_redirect} \n ----\n size: %{size_download}\n" "https://www.baidu.com"
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus=autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn" autofocus></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新聞</a> <a href=https://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地圖</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>視頻</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>貼吧</a> <noscript> <a href=http://m.jungjaehyung.com/uploadfile/2024/1011/20241011104128743.gif?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登錄</a> </noscript> <script>document.write('<a href="http://m.jungjaehyung.com/uploadfile/2024/1011/20241011104128743.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search==="" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登錄</a>');
</script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多產品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>關于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>?2017 Baidu <a href=http://www.baidu.com/duty/>使用百度前必讀</a> <a href=http://jianyi.baidu.com/ class=cp-feedback>意見反饋</a> 京ICP證030173號 <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>
Result:
dnslookup: 0.005
connect: 0.009
appconnect: 0.128
pretransfer: 0.128
starttransfer: 0.134
total: 0.134
----
time_redirect: 0.000
----
size: 2443
參數:
從上面的例子可以看到
上面還有個小技巧:
$ cat ~/.curlrc
-w "Result: \n dnslookup: %{time_namelookup} \n connect: %{time_connect} \n appconnect: %{time_appconnect} \n pretransfer: %{time_pretransfer} \n starttransfer: %{time_starttransfer} \n total: %{time_total} \n ----\n time_redirect: %{time_redirect} \n ----\n size: %{size_download}\n"
$ curl "https://www.baidu.com"
我們把-w參數的值寫到curl配置文件~/.curlrc,這樣我們按照之前的curl命令訪問具體網址就可以得到各個時間。
當你擁有Python的環境時,可以借助一個庫,可以方便清晰的了解耗時,這個庫就是httpstat。
注意:該工具還是依賴底層curl命令,所以確保curl是最新版本。
這里我以Python3環境為例,介紹下如何使用。
$ pip3 install httpstat
$ which httpstat
~/3rd/Python-3.7.4/bin/httpstat
$ httpstat "https://www.baidu.com"
Connected to 163.177.151.110:443 from 10.10.10.10:41350
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
Connection: keep-alive
Content-Length: 2443
Content-Type: text/html
Date: Mon, 25 May 2020 03:14:53 GMT
Etag: "58860402-98b"
Last-Modified: Mon, 23 Jan 2017 13:24:18 GMT
Pragma: no-cache
Server: bfe/1.0.8.18
Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/
Body stored in: /tmp/tmp35tdqpkp
DNS Lookup TCP Connection TLS Handshake Server Processing Content Transfer
[ 41ms | 5ms | 45ms | 6ms | 1ms ]
| | | | |
namelookup:41ms | | | |
connect:46ms | | |
pretransfer:91ms | |
starttransfer:97ms |
total:98ms
是不是很直觀? so easy。
今天你get 到了嗎?喜歡的話,關注收藏下。
GINX主要設計作為反向代理服務器,但隨著NGINX的發展,它同樣能作為正向代理的選項之一。正向代理本身并不復雜,而如何代理加密的HTTPS流量是正向代理需要解決的主要問題。本文將介紹利用NGINX來正向代理HTTPS流量兩種方案,及其使用場景和主要問題。
簡單介紹下正向代理的分類作為理解下文的背景知識:
按客戶端有無感知的分類
按代理是否解密HTTPS的分類
https://www.jianshu.com/p/405f9d76f8c4
作為反向代理時,代理服務器通常終結 (terminate) HTTPS加密流量,再轉發給后端實例。HTTPS流量的加解密和認證過程發生在客戶端和反向代理服務器之間。
而作為正向代理在處理客戶端發過來的流量時,HTTP加密封裝在了TLS/SSL中,代理服務器無法看到客戶端請求URL中想要訪問的域名,如下圖。所以代理HTTPS流量,相比于HTTP,需要做一些特殊處理。
根據前文中的分類方式,NGINX解決HTTPS代理的方式都屬于透傳(隧道)模式,即不解密不感知上層流量。具體的方式有如下7層和4層的兩類解決方案。
HTTP CONNECT隧道 (7層解決方案)
歷史背景
早在1998年,也就是TLS還沒有正式誕生的SSL時代,主導SSL協議的Netscape公司就提出了關于利用web代理來tunneling SSL流量的INTERNET-DRAFT。其核心思想就是利用HTTP CONNECT請求在客戶端和代理之間建立一個HTTP CONNECT Tunnel,在CONNECT請求中需要指定客戶端需要訪問的目的主機和端口。Draft中的原圖如下:
整個過程可以參考HTTP權威指南中的圖:
NGINX ngx_http_proxy_connect_module模塊
NGINX作為反向代理服務器,官方一直沒有支持HTTP CONNECT方法。但是基于NGINX的模塊化、可擴展性好的特性,阿里的@chobits提供了ngx_http_proxy_connect_module模塊,來支持HTTP CONNECT方法,從而讓NGINX可以擴展為正向代理。
環境搭建
以CentOS 7的環境為例。
1) 安裝
對于新安裝的環境,參考正常的安裝步驟和安裝這個模塊的步驟(https://github.com/chobits/ngx_http_proxy_connect_module),把對應版本的patch打上之后,在configure的時候加上參數--add-module=/path/to/ngx_http_proxy_connect_module,示例如下:
./configure \ --user=www \ --group=www \ --prefix=/usr/local/nginx \ --with-http_ssl_module \ --with-http_stub_status_module \ --with-http_realip_module \ --with-threads \ --add-module=/root/src/ngx_http_proxy_connect_module
對于已經安裝編譯安裝完的環境,需要加入以上模塊,步驟如下:
# 停止NGINX服務 # systemctl stop nginx # 備份原執行文件 # cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.bak # 在源代碼路徑重新編譯 # cd /usr/local/src/nginx-1.16.0 ./configure \ --user=www \ --group=www \ --prefix=/usr/local/nginx \ --with-http_ssl_module \ --with-http_stub_status_module \ --with-http_realip_module \ --with-threads \ --add-module=/root/src/ngx_http_proxy_connect_module # make # 不要make install # 將新生成的可執行文件拷貝覆蓋原來的nginx執行文件 # cp objs/nginx /usr/local/nginx/sbin/nginx # /usr/bin/nginx -V nginx version: nginx/1.16.0 built by gcc 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC) built with OpenSSL 1.0.2k-fips 26 Jan 2017 TLS SNI support enabled configure arguments: --user=www --group=www --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-threads --add-module=/root/src/ngx_http_proxy_connect_module
2) nginx.conf文件配置
server { listen 443; # dns resolver used by forward proxying resolver 114.114.114.114; # forward proxy for CONNECT request proxy_connect; proxy_connect_allow 443; proxy_connect_connect_timeout 10s; proxy_connect_read_timeout 10s; proxy_connect_send_timeout 10s; # forward proxy for non-CONNECT request location / { proxy_pass http://$host; proxy_set_header Host $host; } }
使用場景
7層需要通過HTTP CONNECT來建立隧道,屬于客戶端有感知的普通代理方式,需要在客戶端手動配置HTTP(S)代理服務器IP和端口。在客戶端用curl 加-x參數訪問如下:
# curl https://www.baidu.com -svo /dev/null -x 39.105.196.164:443 * About to connect() to proxy 39.105.196.164 port 443 (#0) * Trying 39.105.196.164... * Connected to 39.105.196.164 (39.105.196.164) port 443 (#0) * Establish HTTP proxy tunnel to www.baidu.com:443 > CONNECT www.baidu.com:443 HTTP/1.1 > Host: www.baidu.com:443 > User-Agent: curl/7.29.0 > Proxy-Connection: Keep-Alive > < HTTP/1.1 200 Connection Established < Proxy-agent: nginx < * Proxy replied OK to CONNECT request * Initializing NSS with certpath: sql:/etc/pki/nssdb * CAfile: /etc/pki/tls/certs/ca-bundle.crt CApath: none * SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 * Server certificate: * subject: CN=baidu.com,O="Beijing Baidu Netcom Science Technology Co., Ltd",OU=service operation department,L=beijing,ST=beijing,C=CN ... > GET / HTTP/1.1 > User-Agent: curl/7.29.0 > Host: www.baidu.com > Accept: */* > < HTTP/1.1 200 OK ... { [data not shown]
從上面-v參數打印出的細節,可以看到客戶端先往代理服務器39.105.196.164建立了HTTP CONNECT隧道,代理回復HTTP/1.1 200 Connection Established后就開始交互TLS/SSL握手和流量了。
NGINX stream (4層解決方案)
既然是使用透傳上層流量的方法,那可不可做成“4層代理”,對TCP/UDP以上的協議實現徹底的透傳呢?答案是可以的。NGINX官方從1.9.0版本開始支持ngx_stream_core_module模塊,模塊默認不build,需要configure時加上--with-stream選項來開啟。
問題
用NGINX stream在TCP層面上代理HTTPS流量肯定會遇到本文一開始提到的那個問題:代理服務器無法獲取客戶端想要訪問的目的域名。因為在TCP的層面獲取的信息僅限于IP和端口層面,沒有任何機會拿到域名信息。要拿到目的域名,必須要有拆上層報文獲取域名信息的能力,所以NGINX stream的方式不是完全嚴格意義上的4層代理,還是要略微借助些上層能力。
ngx_stream_ssl_preread_module模塊
要在不解密的情況下拿到HTTPS流量訪問的域名,只有利用TLS/SSL握手的第一個Client Hello報文中的擴展地址SNI (Server Name Indication)來獲取。NGINX官方從1.11.5版本開始支持利用ngx_stream_ssl_preread_module模塊來獲得這個能力,模塊主要用于獲取Client Hello報文中的SNI和ALPN信息。對于4層正向代理來說,從Client Hello報文中提取SNI的能力是至關重要的,否則NGINX stream的解決方案無法成立。同時這也帶來了一個限制,要求所有客戶端都需要在TLS/SSL握手中帶上SNI字段,否則NGINX stream代理完全沒辦法知道客戶端需要訪問的目的域名。
環境搭建
1) 安裝
對于新安裝的環境,參考正常的安裝步驟,直接在configure的時候加上--with-stream,--with-stream_ssl_preread_module和--with-stream_ssl_module選項即可。示例如下:
./configure \ --user=www \ --group=www \ --prefix=/usr/local/nginx \ --with-http_ssl_module \ --with-http_stub_status_module \ --with-http_realip_module \ --with-threads \ --with-stream \ --with-stream_ssl_preread_module \ --with-stream_ssl_module
對于已經安裝編譯安裝完的環境,需要加入以上3個與stream相關的模塊,步驟如下:
# 停止NGINX服務 # systemctl stop nginx # 備份原執行文件 # cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.bak # 在源代碼路徑重新編譯 # cd /usr/local/src/nginx-1.16.0 # ./configure \ --user=www \ --group=www \ --prefix=/usr/local/nginx \ --with-http_ssl_module \ --with-http_stub_status_module \ --with-http_realip_module \ --with-threads \ --with-stream \ --with-stream_ssl_preread_module \ --with-stream_ssl_module # make # 不要make install # 將新生成的可執行文件拷貝覆蓋原來的nginx執行文件 # cp objs/nginx /usr/local/nginx/sbin/nginx # nginx -V nginx version: nginx/1.16.0 built by gcc 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC) built with OpenSSL 1.0.2k-fips 26 Jan 2017 TLS SNI support enabled configure arguments: --user=www --group=www --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-threads --with-stream --with-stream_ssl_preread_module --with-stream_ssl_module
2) nginx.conf文件配置
NGINX stream與HTTP不同,需要在stream塊中進行配置,但是指令參數與HTTP塊都是類似的,主要配置部分如下:
stream { resolver 114.114.114.114; server { listen 443; ssl_preread on; proxy_connect_timeout 5s; proxy_pass $ssl_preread_server_name:$server_port; } }
使用場景
對于4層正向代理,NGINX對上層流量基本上是透傳,也不需要HTTP CONNECT來建立隧道。適合于透明代理的模式,比如將訪問的域名利用DNS解定向到代理服務器。我們可以通過在客戶端綁定/etc/hosts來模擬。
在客戶端:
cat /etc/hosts ... # 把域名www.baidu.com綁定到正向代理服務器39.105.196.164 39.105.196.164 www.baidu.com # 正常利用curl來訪問www.baidu.com即可。 # curl https://www.baidu.com -svo /dev/null * About to connect() to www.baidu.com port 443 (#0) * Trying 39.105.196.164... * Connected to www.baidu.com (39.105.196.164) port 443 (#0) * Initializing NSS with certpath: sql:/etc/pki/nssdb * CAfile: /etc/pki/tls/certs/ca-bundle.crt CApath: none * SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 * Server certificate: * subject: CN=baidu.com,O="Beijing Baidu Netcom Science Technology Co., Ltd",OU=service operation department,L=beijing,ST=beijing,C=CN * start date: 5月 09 01:22:02 2019 GMT * expire date: 6月 25 05:31:02 2020 GMT * common name: baidu.com * issuer: CN=GlobalSign Organization Validation CA - SHA256 - G2,O=GlobalSign nv-sa,C=BE > GET / HTTP/1.1 > User-Agent: curl/7.29.0 > Host: www.baidu.com > Accept: */* > < HTTP/1.1 200 OK < Accept-Ranges: bytes < Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform < Connection: Keep-Alive < Content-Length: 2443 < Content-Type: text/html < Date: Fri, 21 Jun 2019 05:46:07 GMT < Etag: "5886041d-98b" < Last-Modified: Mon, 23 Jan 2017 13:24:45 GMT < Pragma: no-cache < Server: bfe/1.0.8.18 < Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/ < { [data not shown] * Connection #0 to host www.baidu.com left intact
常見問題
1) 客戶端手動設置代理導致訪問不成功
4層正向代理是透傳上層HTTPS流量,不需要HTTP CONNECT來建立隧道,也就是說不需要客戶端設置HTTP(S)代理。如果我們在客戶端手動設置HTTP(s)代理是否能訪問成功呢? 我們可以用curl -x來設置代理為這個正向服務器訪問測試,看看結果:
# curl https://www.baidu.com -svo /dev/null -x 39.105.196.164:443 * About to connect() to proxy 39.105.196.164 port 443 (#0) * Trying 39.105.196.164... * Connected to 39.105.196.164 (39.105.196.164) port 443 (#0) * Establish HTTP proxy tunnel to www.baidu.com:443 > CONNECT www.baidu.com:443 HTTP/1.1 > Host: www.baidu.com:443 > User-Agent: curl/7.29.0 > Proxy-Connection: Keep-Alive > * Proxy CONNECT aborted * Connection #0 to host 39.105.196.164 left intact
可以看到客戶端試圖于正向NGINX前建立HTTP CONNECT tunnel,但是由于NGINX是透傳,所以把CONNECT請求直接轉發給了目的服務器。目的服務器不接受CONNECT方法,所以最終出現"Proxy CONNECT aborted",導致訪問不成功。
2) 客戶端沒有帶SNI導致訪問不成功
上文提到用NGINX stream做正向代理的關鍵因素之一是利用ngx_stream_ssl_preread_module提取出Client Hello中的SNI字段。如果客戶端客戶端不攜帶SNI字段,會造成代理服務器無法獲知目的域名的情況,導致訪問不成功。
在透明代理模式下(用手動綁定hosts的方式模擬),我們可以在客戶端用openssl來模擬:
# openssl s_client -connect www.baidu.com:443 -msg CONNECTED(00000003) >>> TLS 1.2 [length 0005] 16 03 01 01 1c >>> TLS 1.2 Handshake [length 011c], ClientHello 01 00 01 18 03 03 6b 2e 75 86 52 6c d5 a5 80 d7 a4 61 65 6d 72 53 33 fb 33 f0 43 a3 aa c2 4a e3 47 84 9f 69 8b d6 00 00 ac c0 30 c0 2c c0 28 c0 24 c0 14 c0 0a 00 a5 00 a3 00 a1 00 9f 00 6b 00 6a 00 69 00 68 00 39 00 38 00 37 00 36 00 88 00 87 00 86 00 85 c0 32 c0 2e c0 2a c0 26 c0 0f c0 05 00 9d 00 3d 00 35 00 84 c0 2f c0 2b c0 27 c0 23 c0 13 c0 09 00 a4 00 a2 00 a0 00 9e 00 67 00 40 00 3f 00 3e 00 33 00 32 00 31 00 30 00 9a 00 99 00 98 00 97 00 45 00 44 00 43 00 42 c0 31 c0 2d c0 29 c0 25 c0 0e c0 04 00 9c 00 3c 00 2f 00 96 00 41 c0 12 c0 08 00 16 00 13 00 10 00 0d c0 0d c0 03 00 0a 00 07 c0 11 c0 07 c0 0c c0 02 00 05 00 04 00 ff 01 00 00 43 00 0b 00 04 03 00 01 02 00 0a 00 0a 00 08 00 17 00 19 00 18 00 16 00 23 00 00 00 0d 00 20 00 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 140285606590352: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 289 bytes ...
openssl s_client默認不帶SNI,可以看到上面的請求在TLS/SSL握手階段,發出Client Hello后就結束了。因為代理服務器不知道要把Client Hello往哪個目的域名轉發。
如果用openssl帶servername參數來指定SNI,則可以正常訪問成功,命令如下:
# openssl s_client -connect www.baidu.com:443 -servername www.baidu.com
本文總結了NGINX利用HTTP CONNECT隧道和NGINX stream兩種方式做HTTPS正向代理的原理,環境搭建,使用場景和主要問題,希望給大家在做各種場景的正向代理時提供參考。
作者:懷知
者 | LightZhang666
責編 | 屠敏
出品 | CSDN 博客
本篇文章包含了curl的常用案例使用。
常見網頁訪問示例
基本用法
訪問一個網頁:
curl https://www.baidu.com
執行后,相關的網頁信息會打印出來。
進度條展示
有時候我們不需要進度表展示,而需要進度條展示。比如:下載文件時。
可以通過 -#, --progress-bar 選項實現。
[root@iZ28xbsfvc4Z 20190713]# curl https://www.baidu.com | head -n1 # 進度表顯示
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 2443 100 2443 0 0 11662 0 --:--:-- --:--:-- --:--:-- 11688
<!DOCTYPE html>
[root@iZ28xbsfvc4Z 20190713]# curl -# https://www.baidu.com | head -n1 # 進度條顯示
######################################################################## 100.0%
<!DOCTYPE html>
靜默模式與錯誤信息打印
當我們做一些操作時,可能會出現進度表。這時我們可以使用 -s, --silent 靜默模式去掉這些不必要的信息。
如果使用 -s, --silent 時,還需要打印錯誤信息,那么還需要使用 -S, --show-error 選項。
靜默模式示例
[root@iZ28xbsfvc4Z ~]# curl https://www.baidu.com | head -n1
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 2443 100 2443 0 0 11874 0 --:--:-- --:--:-- --:--:-- 11859
<!DOCTYPE html>
[root@iZ28xbsfvc4Z ~]# curl -s https://www.baidu.com | head -n1
<!DOCTYPE html>
靜默模式結合錯誤信息打印
[root@iZ28xbsfvc4Z 20190713]# curl -s https://140.205.16.113/
[root@iZ28xbsfvc4Z 20190713]#
[root@iZ28xbsfvc4Z 20190713]# curl -sS https://140.205.16.113/
curl: (51) Unable to communicate securely with peer: requested domain name does not match the server's certificate.
顯示詳細操作信息
使用 -v, --verbose 選項實現。
以 > 開頭的行表示curl發送的"header data";< 表示curl接收到的通常情況下隱藏的"header data";而以 * 開頭的行表示curl提供的附加信息。
[root@iZ28xbsfvc4Z 20190712]# curl -v https://www.baidu.com
* About to connect to www.baidu.com port 443 (#0)
* Trying 180.101.49.12...
* Connected to www.baidu.com (180.101.49.12) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* CAfile: /etc/pki/tls/certs/ca-bundle.crt
CApath: none
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
* subject: CN=baidu.com,O="Beijing Baidu Netcom Science Technology Co., Ltd",OU=service operation department,L=beijing,ST=beijing,C=CN
* start date: May 09 01:22:02 2019 GMT
* expire date: Jun 25 05:31:02 2020 GMT
* common name: baidu.com
* issuer: CN=GlobalSign Organization Validation CA - SHA256 - G2,O=GlobalSign nv-sa,C=BE
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: www.baidu.com
> Accept: */*
>
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
< Connection: Keep-Alive
< Content-Length: 2443
< Content-Type: text/html
< Date: Fri, 12 Jul 2019 08:26:23 GMT
< Etag: "588603eb-98b"
< Last-Modified: Mon, 23 Jan 2017 13:23:55 GMT
< Pragma: no-cache
< Server: bfe/1.0.8.18
< Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/
<
<!DOCTYPE html>
……………… # curl 網頁的具體信息
指定訪問的請求方法
當然curl默認使用GET方式訪問。使用了 -d, --data <data> 選項,那么會默認為 POST方法訪問。如果此時還想實現 GET 訪問,那么可以使用 -G, --get 選項強制curl 使用GET方法訪問。
同時 -X, --request <command> 選項也可以指定訪問方法。
POST請求和數據傳輸
為了抓包查看信息所以使用了 --local-port <num>[-num] 選項,在實際應用中不需要該選項。
[root@iZ28xbsfvc4Z ~]# curl -sv --local-port 9000 -X POST -d 'user=zhang&pwd=123456' http://www.zhangblog.com/2019/06/24/domainexpire/ | head -n1
## 或者
[root@iZ28xbsfvc4Z ~]# curl -sv --local-port 9000 -d 'user=zhang&pwd=123456' http://www.zhangblog.com/2019/06/24/domainexpire/ | head -n1
* About to connect to www.zhangblog.com port 80 (#0)
* Trying 120.27.48.179...
* Connected to www.zhangblog.com (120.27.48.179) port 80 (#0)
> POST /2019/06/24/domainexpire/ HTTP/1.1 # POST 請求方法
> User-Agent: curl/7.29.0
> Host: www.zhangblog.com
> Accept: */*
> Content-Length: 21
> Content-Type: application/x-www-form-urlencoded
>
} [data not shown]
* upload completely sent off: 21 out of 21 bytes
< HTTP/1.1 405 Not Allowed
< Server: nginx/1.14.2
< Date: Thu, 18 Jul 2019 07:56:23 GMT
< Content-Type: text/html
< Content-Length: 173
< Connection: keep-alive
<
{ [data not shown]
* Connection #0 to host www.zhangblog.com left intact
<html>
抓包信息
[root@iZ28xbsfvc4Z tcpdump]# tcpdump -i any port 9000 -A -s 0
指定請求方法
curl -vs -X POST https://www.baidu.com | head -n1
curl -vs -X PUT https://www.baidu.com | head -n1
保存訪問網頁
使用linux的重定向功能保存
curl www.baidu.com >> baidu.html
使用curl的大O選項
通過 -O, --remote-name 選項實現。
[root@iZ28xbsfvc4Z 20190712]# curl -O https://www.baidu.com # 使用了 -O 選項,必須指定到具體的文件 錯誤使用
curl: Remote file name has no length!
curl: try 'curl --help' or 'curl --manual' for more information
[root@iZ28xbsfvc4Z 20190712]# curl -O https://www.baidu.com/index.html # 使用了 -O 選項,必須指定到具體的文件 正確使用
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 2443 100 2443 0 0 13289 0 --:--:-- --:--:-- --:--:-- 13349
使用curl的小o選項
通過 -o, --output <file> 選項實現。
[root@iZ28xbsfvc4Z 20190713]# curl -o sina.txt https://www.sina.com.cn/ # 單個操作
[root@iZ28xbsfvc4Z 20190713]# ll
-rw-r--r-- 1 root root 154 Jul 13 21:06 sina.txt
[root@iZ28xbsfvc4Z 20190703]# curl "http://www.{baidu,douban}.com" -o "site_#1.txt" # 批量操作,注意curl 的地址需要用引號括起來
[1/2]: http://www.baidu.com --> site_baidu.txt
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 2381 100 2381 0 0 46045 0 --:--:-- --:--:-- --:--:-- 46686
[2/2]: http://www.douban.com --> site_douban.txt
100 162 100 162 0 0 3173 0 --:--:-- --:--:-- --:--:-- 3173
[root@iZ28xbsfvc4Z 20190703]#
[root@iZ28xbsfvc4Z 20190703]# ll
total 220
-rw-r--r-- 1 root root 2381 Jul 4 16:53 site_baidu.txt
-rw-r--r-- 1 root root 162 Jul 4 16:53 site_douban.txt
允許不安全訪問
當我們使用curl進行https訪問訪問時,如果SSL證書是我們自簽發的證書,那么這個時候需要使用 -k, --insecure 選項,允許不安全的訪問。
[root@iZ28xbsfvc4Z ~]# curl https://140.205.16.113/ # 被拒絕
curl: (51) Unable to communicate securely with peer: requested domain name does not match the server's certificate.
[root@iZ28xbsfvc4Z ~]#
[root@iZ28xbsfvc4Z ~]# curl -k https://140.205.16.113/ # 允許執行不安全的證書連接
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<h1>403 Forbidden</h1>
<p>You don't have permission to access the URL on this server.<hr/>Powered by Tengine</body>
</html>
獲取HTTP響應狀態碼
在腳本中,這是很常見的測試網站是否正常的用法。
通過 -w, --write-out <format> 選項實現。
[root@iZ28xbsfvc4Z 20190713]# curl -o /dev/ -s -w %{http_code} https://baidu.com
302[root@iZ28xbsfvc4Z 20190713]#
[root@iZ28xbsfvc4Z 20190713]#
[root@iZ28xbsfvc4Z 20190713]# curl -o /dev/ -s -w %{http_code} https://www.baidu.com
200[root@iZ28xbsfvc4Z 20190713]#
指定proxy服務器以及其端口
很多時候上網需要用到代理服務器(比如是使用代理服務器上網或者因為使用curl別人網站而被別人屏蔽IP地址的時候),幸運的是curl通過使用 -x, --proxy <[protocol://][user:password@]proxyhost[:port]> 選項來支持設置代理。
curl -x 192.168.100.100:1080 https://www.baidu.com
模仿瀏覽器訪問
有些網站需要使用特定的瀏覽器去訪問他們,有些還需要使用某些特定的瀏覽器版本。我們可以通過 -A, --user-agent <agent string> 或者 -H, --header <header> 選項實現模擬瀏覽器訪問。
curl -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/75.0.3770.999" http://www.zhangblog.com/2019/06/24/domainexpire/
或者
curl -H 'User-Agent: Mozilla/5.0' http://www.zhangblog.com/2019/06/24/domainexpire/
偽造referer(盜鏈)
有些網站的網頁對http訪問的鏈接來源做了訪問限制,這些限制幾乎都是通過referer來實現的。
比如:要求是先訪問首頁,然后再訪問首頁中的郵箱頁面,這時訪問郵箱的referer地址就是訪問首頁成功后的頁面地址。如果服務器發現對郵箱頁面訪問的referer地址不是首頁的地址,就斷定那是個盜連了。
可以通過 -e, --referer 或則 -H, --header <header> 實現偽造 referer 。
curl -e 'https://www.baidu.com' http://www.zhangblog.com/2019/06/24/domainexpire/
或者
curl -H 'Referer: https://www.baidu.com' http://www.zhangblog.com/2019/06/24/domainexpire/
構造HTTP請求頭
可以通過 -H, --header <header> 實現構造http請求頭。
curl -H 'Connection: keep-alive' -H 'Referer: https://sina.com.cn' -H 'User-Agent: Mozilla/1.0' http://www.zhangblog.com/2019/06/24/domainexpire/
保存響應頭信息
可以通過 -D, --dump-header <file> 選項實現。
[root@iZ28xbsfvc4Z 20190703]# curl -D baidu_header.info www.baidu.com
………………
[root@iZ28xbsfvc4Z 20190703]# ll
total 4
-rw-r--r-- 1 root root 400 Jul 3 10:11 baidu_header.info # 生成的頭文件
限時訪問
--connect-timeout <seconds> 連接服務端的超時時間。這只限制了連接階段,一旦curl連接了此選項就不再使用了。
# 當前 https://www.zhangXX.com 是國外服務器,訪問受限
[root@iZ28xbsfvc4Z ~]# curl --connect-timeout 10 https://www.zhangXX.com | head
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- 0:00:10 --:--:-- 0
curl: (28) Connection timed out after 10001 milliseconds
-m, --max-time <seconds> 允許整個操作花費的最大時間(以秒為單位)。這對于防止由于網絡或鏈接變慢而導致批處理作業掛起數小時非常有用。
[root@iZ28xbsfvc4Z ~]# curl -m 10 --limit-rate 5 http://www.baidu.com/ | head # 超過10秒后,斷開連接
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
2 2381 2 50 0 0 4 0 0:09:55 0:00:10 0:09:45 4
curl: (28) Operation timed out after 10103 milliseconds with 50 out of 2381 bytes received
<!DOCTYPE html>
<!--STATUS OK--><html> <head><met
### 或
[root@iZ28xbsfvc4Z ~]# curl -m 10 https://www.zhangXX.com | head # 超過10秒后,斷開連接
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- 0:00:10 --:--:-- 0
curl: (28) Connection timed out after 10001 milliseconds
顯示抓取錯誤
當我們請求訪問失敗時或者沒有該網頁時,網站一般都會給出一個錯誤的提示頁面。
如果我們不需要這個錯誤頁面,只想得到簡潔的錯誤信息。那么可以通過 -f, --fail 選項實現。
[root@iZ28xbsfvc4Z 20190713]# curl http://www.zhangblog.com/201912312
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.14.2</center>
</body>
</html>
[root@iZ28xbsfvc4Z 20190713]# curl -f http://www.zhangblog.com/201912312 # 得到更簡潔的錯誤信息
curl: (22) The requested URL returned error: 404 Not Found
表單登錄與cookie使用
參見「Linux curl 表單登錄或提交與cookie使用」:http://www.zhangblog.com/2019/07/20/curl03/
文件上傳與下載
涉及 FTP 服務,簡單快速搭建可參考:《CentOS7下安裝FTP服務》「https://www.cnblogs.com/zhi-leaf/p/5983550.html」
文件下載網頁文件下載
# 以進度條展示,而不是進度表展示
[root@iZ28xbsfvc4Z 20190715]# curl -# -o tmp.data2 http://www.zhangblog.com/uploads/tmp/tmp.data
######################################################################## 100.0%
FTP文件下載
說明1:其中 ftp1 用戶是ftp服務端的賬號,具體家目錄是:/mnt/ftp1
說明2:當我們使用 curl 通過 FTP 進行下載時,后面跟的路徑都是:當前使用的 ftp 賬號家目錄為基礎的相對路徑,然后找到的目標文件。
示例1
# 其中 tmp.data 的絕對路徑是:/mnt/ftp1/tmpdata/tmp.data ;ftp1 賬號的家目錄是:/mnt/ftp1
# 說明:/tmpdata/tmp.data 這個路徑是針對 ftp1 賬號的家目錄而言的
[yun@nginx_proxy01 20190715]$ curl -O ftp://ftp1:123456@172.16.1.195:21/tmpdata/tmp.data
# 或者
[yun@nginx_proxy01 20190715]$ curl -O -u ftp1:123456 ftp://172.16.1.195:21/tmpdata/tmp.data
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 2048M 100 2048M 0 0 39.5M 0 0:00:51 0:00:51 --:--:-- 143M
示例2
# 其中 nginx-1.14.2.tar.gz 的絕對路徑是:/tmp/nginx-1.14.2.tar.gz ;ftp1 賬號的家目錄是:/mnt/ftp1
# 說明:/../../tmp/nginx-1.14.2.tar.gz 這個路徑是針對 ftp1 賬號的家目錄而言的
[yun@nginx_proxy01 20190715]$ curl -O ftp://ftp1:123456@172.16.1.195:21/../../tmp/nginx-1.14.2.tar.gz
# 或者
[yun@nginx_proxy01 20190715]$ curl -O -u ftp1:123456 ftp://172.16.1.195:21/../../tmp/nginx-1.14.2.tar.gz
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 991k 100 991k 0 0 5910k 0 --:--:-- --:--:-- --:--:-- 5937k
文件上傳
FTP文件上傳
可以通過 -T, --upload-file <file> 選項實現。
說明1:其中 ftp1 用戶是ftp服務端的賬號,具體家目錄是:/mnt/ftp1
# 其中 tmp_client.data 是客戶端本地文件;
# /tmpdata/ 這個路徑是針對 ftp1 賬號的家目錄而言的,且上傳時該目錄必須是存在的,否則上傳失敗。
# 因此上傳后文件在ftp服務端的絕對路徑是:/mnt/ftp1/tmpdata/tmp_client.data
[yun@nginx_proxy01 20190715]$ curl -T tmp_client.data ftp://ftp1:123456@172.16.1.195:21/tmpdata/
# 或者
[yun@nginx_proxy01 20190715]$ curl -T tmp_client.data -u ftp1:123456 ftp://172.16.1.195:21/tmpdata/
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 2048M 0 0 100 2048M 0 95.4M 0:00:21 0:00:21 --:--:-- 49.3M
斷點續傳
使用 -C, --continue-at <offset> 選項實現。其中使用 “-C -”「注意有空格和無空格的情況」,告訴curl自動找出在哪里/如何恢復傳輸。
網頁端斷點續傳下載
curl -C - -o tmp.data http://www.zhangblog.com/uploads/tmp/tmp.data # 下載一個 2G 的文件
FTP斷點續傳下載
細節就不多說了,可參見上面的「FTP文件下載」
curl -C - -o tmp.data1 ftp://ftp1:123456@172.16.1.195:21/tmpdata/tmp.data # 下載一個 2G 的文件
# 或則
curl -C - -o tmp.data1 -u ftp1:123456 ftp://172.16.1.195:21/tmpdata/tmp.data # 下載一個 2G 的文件
分段下載
有時文件比較大,或者難以迅速傳輸,而利用分段傳輸,可以實現穩定、高效并且有保障的傳輸,更具有實用性,同時容易對差錯文件進行更正。
可使用 -r, --range <range> 選項實現。
如下示例使用了同一張圖片,大小為 18196 字節。
網頁端分段下載分段下載
[root@iZ28xbsfvc4Z 20190715]# curl -I http://www.zhangblog.com/uploads/hexo/00.jpg # 查看文件大小
HTTP/1.1 200 OK
Server: nginx/1.14.2
Date: Mon, 15 Jul 2019 03:23:44 GMT
Content-Type: image/jpeg
Content-Length: 18196 # 文件大小
Last-Modified: Fri, 05 Jul 2019 08:04:58 GMT
Connection: keep-alive
ETag: "5d1f04aa-4714"
Accept-Ranges: bytes
### 分段下載一個文件
[root@iZ28xbsfvc4Z 20190715]# curl -r 0-499 -o 00-jpg.part1 http://www.zhangblog.com/uploads/hexo/00.jpg
[root@iZ28xbsfvc4Z 20190715]# curl -r 500-999 -o 00-jpg.part2 http://www.zhangblog.com/uploads/hexo/00.jpg
[root@iZ28xbsfvc4Z 20190715]# curl -r 1000- -o 00-jpg.part3 http://www.zhangblog.com/uploads/hexo/00.jpg
查看下載文件
[root@iZ28xbsfvc4Z 20190715]# ll
total 36
-rw-r--r-- 1 root root 500 Jul 15 11:25 00-jpg.part1
-rw-r--r-- 1 root root 500 Jul 15 11:25 00-jpg.part2
-rw-r--r-- 1 root root 17196 Jul 15 11:26 00-jpg.part3
文件合并
[root@iZ28xbsfvc4Z 20190715]# cat 00-jpg.part1 00-jpg.part2 00-jpg.part3 > 00.jpg
[root@iZ28xbsfvc4Z 20190715]# ll 00.jpg
total 56
-rw-r--r-- 1 root root 18196 Jul 15 11:29 00.jpg
FTP分段下載分段下載
[yun@nginx_proxy01 20190715]$ curl -r 0-499 -o 00-jpg.part1 ftp://ftp1:123456@172.16.1.195:21/tmpdata/00.jpg
[yun@nginx_proxy01 20190715]$ curl -r 500-999 -o 00-jpg.part2 ftp://ftp1:123456@172.16.1.195:21/tmpdata/00.jpg
[yun@nginx_proxy01 20190715]$ curl -r 1000- -o 00-jpg.part3 ftp://ftp1:123456@172.16.1.195:21/tmpdata/00.jpg
查看下載文件
[yun@nginx_proxy01 20190715]$ ll 00-jpg.part*
-rw-rw-r-- 1 yun yun 500 Jul 15 17:59 00-jpg.part1
-rw-rw-r-- 1 yun yun 500 Jul 15 18:00 00-jpg.part2
-rw-rw-r-- 1 yun yun 17196 Jul 15 18:00 00-jpg.part3
文件合并
[yun@nginx_proxy01 20190715]$ cat 00-jpg.part1 00-jpg.part2 00-jpg.part3 > 00.jpg
[yun@nginx_proxy01 20190715]$ ll 00.jpg
-rw-rw-r-- 1 yun yun 18196 Jul 15 18:02 00.jpg
聲明:本文為CSDN博主「LightZhang666」的原創文章,版權歸作者所有,如需轉載請聯系作者。
原文:https://blog.csdn.net/woshizhangliang999/article/details/98946071
【End】
*請認真填寫需求信息,我們會在24小時內與您取得聯系。