Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
當(dāng)我們訪問一個(gè)網(wǎng)站或者網(wǎng)站接口服務(wù),想知道"時(shí)間都去哪里了",這時(shí)候我們借助工具來分析。
可以將時(shí)間大致分為兩部分:一部分是從我們請求到網(wǎng)站服務(wù)端所經(jīng)歷的耗時(shí),另一部分是服務(wù)端自身處理該服務(wù)完畢后響應(yīng)回來的時(shí)間,這些都是可以作為后面結(jié)果分析的判斷依據(jù)。
下面將介紹兩個(gè)方案,僅供參考。
開始計(jì)時(shí)
使用系統(tǒng)curl命令模擬網(wǎng)站服務(wù)請求,得到各個(gè)時(shí)間段的時(shí)間。
需要注意的是:請確保curl 是最新版本,否則一些參數(shù)選項(xiàng)無法使用。
例子:
$ 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;">更多產(chǎn)品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>關(guān)于百度</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號(hào) <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
參數(shù):
從上面的例子可以看到
上面還有個(gè)小技巧:
$ 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參數(shù)的值寫到curl配置文件~/.curlrc,這樣我們按照之前的curl命令訪問具體網(wǎng)址就可以得到各個(gè)時(shí)間。
當(dāng)你擁有Python的環(huán)境時(shí),可以借助一個(gè)庫,可以方便清晰的了解耗時(shí),這個(gè)庫就是httpstat。
注意:該工具還是依賴底層curl命令,所以確保curl是最新版本。
這里我以Python3環(huán)境為例,介紹下如何使用。
$ 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 到了嗎?喜歡的話,關(guān)注收藏下。
GINX主要設(shè)計(jì)作為反向代理服務(wù)器,但隨著NGINX的發(fā)展,它同樣能作為正向代理的選項(xiàng)之一。正向代理本身并不復(fù)雜,而如何代理加密的HTTPS流量是正向代理需要解決的主要問題。本文將介紹利用NGINX來正向代理HTTPS流量兩種方案,及其使用場景和主要問題。
簡單介紹下正向代理的分類作為理解下文的背景知識(shí):
按客戶端有無感知的分類
按代理是否解密HTTPS的分類
https://www.jianshu.com/p/405f9d76f8c4
作為反向代理時(shí),代理服務(wù)器通常終結(jié) (terminate) HTTPS加密流量,再轉(zhuǎn)發(fā)給后端實(shí)例。HTTPS流量的加解密和認(rèn)證過程發(fā)生在客戶端和反向代理服務(wù)器之間。
而作為正向代理在處理客戶端發(fā)過來的流量時(shí),HTTP加密封裝在了TLS/SSL中,代理服務(wù)器無法看到客戶端請求URL中想要訪問的域名,如下圖。所以代理HTTPS流量,相比于HTTP,需要做一些特殊處理。
根據(jù)前文中的分類方式,NGINX解決HTTPS代理的方式都屬于透傳(隧道)模式,即不解密不感知上層流量。具體的方式有如下7層和4層的兩類解決方案。
HTTP CONNECT隧道 (7層解決方案)
歷史背景
早在1998年,也就是TLS還沒有正式誕生的SSL時(shí)代,主導(dǎo)SSL協(xié)議的Netscape公司就提出了關(guān)于利用web代理來tunneling SSL流量的INTERNET-DRAFT。其核心思想就是利用HTTP CONNECT請求在客戶端和代理之間建立一個(gè)HTTP CONNECT Tunnel,在CONNECT請求中需要指定客戶端需要訪問的目的主機(jī)和端口。Draft中的原圖如下:
整個(gè)過程可以參考HTTP權(quán)威指南中的圖:
NGINX ngx_http_proxy_connect_module模塊
NGINX作為反向代理服務(wù)器,官方一直沒有支持HTTP CONNECT方法。但是基于NGINX的模塊化、可擴(kuò)展性好的特性,阿里的@chobits提供了ngx_http_proxy_connect_module模塊,來支持HTTP CONNECT方法,從而讓NGINX可以擴(kuò)展為正向代理。
環(huán)境搭建
以CentOS 7的環(huán)境為例。
1) 安裝
對于新安裝的環(huán)境,參考正常的安裝步驟和安裝這個(gè)模塊的步驟(https://github.com/chobits/ngx_http_proxy_connect_module),把對應(yīng)版本的patch打上之后,在configure的時(shí)候加上參數(shù)--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
對于已經(jīng)安裝編譯安裝完的環(huán)境,需要加入以上模塊,步驟如下:
# 停止NGINX服務(wù) # systemctl stop nginx # 備份原執(zhí)行文件 # 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 # 將新生成的可執(zhí)行文件拷貝覆蓋原來的nginx執(zhí)行文件 # 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來建立隧道,屬于客戶端有感知的普通代理方式,需要在客戶端手動(dòng)配置HTTP(S)代理服務(wù)器IP和端口。在客戶端用curl 加-x參數(shù)訪問如下:
# 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參數(shù)打印出的細(xì)節(jié),可以看到客戶端先往代理服務(wù)器39.105.196.164建立了HTTP CONNECT隧道,代理回復(fù)HTTP/1.1 200 Connection Established后就開始交互TLS/SSL握手和流量了。
NGINX stream (4層解決方案)
既然是使用透傳上層流量的方法,那可不可做成“4層代理”,對TCP/UDP以上的協(xié)議實(shí)現(xiàn)徹底的透傳呢?答案是可以的。NGINX官方從1.9.0版本開始支持ngx_stream_core_module模塊,模塊默認(rèn)不build,需要configure時(shí)加上--with-stream選項(xiàng)來開啟。
問題
用NGINX stream在TCP層面上代理HTTPS流量肯定會(huì)遇到本文一開始提到的那個(gè)問題:代理服務(wù)器無法獲取客戶端想要訪問的目的域名。因?yàn)樵赥CP的層面獲取的信息僅限于IP和端口層面,沒有任何機(jī)會(huì)拿到域名信息。要拿到目的域名,必須要有拆上層報(bào)文獲取域名信息的能力,所以NGINX stream的方式不是完全嚴(yán)格意義上的4層代理,還是要略微借助些上層能力。
ngx_stream_ssl_preread_module模塊
要在不解密的情況下拿到HTTPS流量訪問的域名,只有利用TLS/SSL握手的第一個(gè)Client Hello報(bào)文中的擴(kuò)展地址SNI (Server Name Indication)來獲取。NGINX官方從1.11.5版本開始支持利用ngx_stream_ssl_preread_module模塊來獲得這個(gè)能力,模塊主要用于獲取Client Hello報(bào)文中的SNI和ALPN信息。對于4層正向代理來說,從Client Hello報(bào)文中提取SNI的能力是至關(guān)重要的,否則NGINX stream的解決方案無法成立。同時(shí)這也帶來了一個(gè)限制,要求所有客戶端都需要在TLS/SSL握手中帶上SNI字段,否則NGINX stream代理完全沒辦法知道客戶端需要訪問的目的域名。
環(huán)境搭建
1) 安裝
對于新安裝的環(huán)境,參考正常的安裝步驟,直接在configure的時(shí)候加上--with-stream,--with-stream_ssl_preread_module和--with-stream_ssl_module選項(xiàng)即可。示例如下:
./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
對于已經(jīng)安裝編譯安裝完的環(huán)境,需要加入以上3個(gè)與stream相關(guān)的模塊,步驟如下:
# 停止NGINX服務(wù) # systemctl stop nginx # 備份原執(zhí)行文件 # 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 # 將新生成的可執(zhí)行文件拷貝覆蓋原來的nginx執(zhí)行文件 # 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塊中進(jìn)行配置,但是指令參數(shù)與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解定向到代理服務(wù)器。我們可以通過在客戶端綁定/etc/hosts來模擬。
在客戶端:
cat /etc/hosts ... # 把域名www.baidu.com綁定到正向代理服務(wù)器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) 客戶端手動(dòng)設(shè)置代理導(dǎo)致訪問不成功
4層正向代理是透傳上層HTTPS流量,不需要HTTP CONNECT來建立隧道,也就是說不需要客戶端設(shè)置HTTP(S)代理。如果我們在客戶端手動(dòng)設(shè)置HTTP(s)代理是否能訪問成功呢? 我們可以用curl -x來設(shè)置代理為這個(gè)正向服務(wù)器訪問測試,看看結(jié)果:
# 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請求直接轉(zhuǎn)發(fā)給了目的服務(wù)器。目的服務(wù)器不接受CONNECT方法,所以最終出現(xiàn)"Proxy CONNECT aborted",導(dǎo)致訪問不成功。
2) 客戶端沒有帶SNI導(dǎo)致訪問不成功
上文提到用NGINX stream做正向代理的關(guān)鍵因素之一是利用ngx_stream_ssl_preread_module提取出Client Hello中的SNI字段。如果客戶端客戶端不攜帶SNI字段,會(huì)造成代理服務(wù)器無法獲知目的域名的情況,導(dǎo)致訪問不成功。
在透明代理模式下(用手動(dòng)綁定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默認(rèn)不帶SNI,可以看到上面的請求在TLS/SSL握手階段,發(fā)出Client Hello后就結(jié)束了。因?yàn)榇矸?wù)器不知道要把Client Hello往哪個(gè)目的域名轉(zhuǎn)發(fā)。
如果用openssl帶servername參數(shù)來指定SNI,則可以正常訪問成功,命令如下:
# openssl s_client -connect www.baidu.com:443 -servername www.baidu.com
本文總結(jié)了NGINX利用HTTP CONNECT隧道和NGINX stream兩種方式做HTTPS正向代理的原理,環(huán)境搭建,使用場景和主要問題,希望給大家在做各種場景的正向代理時(shí)提供參考。
作者:懷知
者 | LightZhang666
責(zé)編 | 屠敏
出品 | CSDN 博客
本篇文章包含了curl的常用案例使用。
常見網(wǎng)頁訪問示例
基本用法
訪問一個(gè)網(wǎng)頁:
curl https://www.baidu.com
執(zhí)行后,相關(guān)的網(wǎng)頁信息會(huì)打印出來。
進(jìn)度條展示
有時(shí)候我們不需要進(jìn)度表展示,而需要進(jìn)度條展示。比如:下載文件時(shí)。
可以通過 -#, --progress-bar 選項(xiàng)實(shí)現(xiàn)。
[root@iZ28xbsfvc4Z 20190713]# curl https://www.baidu.com | head -n1 # 進(jìn)度表顯示
% 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 # 進(jìn)度條顯示
######################################################################## 100.0%
<!DOCTYPE html>
靜默模式與錯(cuò)誤信息打印
當(dāng)我們做一些操作時(shí),可能會(huì)出現(xiàn)進(jìn)度表。這時(shí)我們可以使用 -s, --silent 靜默模式去掉這些不必要的信息。
如果使用 -s, --silent 時(shí),還需要打印錯(cuò)誤信息,那么還需要使用 -S, --show-error 選項(xiàng)。
靜默模式示例
[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>
靜默模式結(jié)合錯(cuò)誤信息打印
[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.
顯示詳細(xì)操作信息
使用 -v, --verbose 選項(xiàng)實(shí)現(xiàn)。
以 > 開頭的行表示curl發(fā)送的"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 網(wǎng)頁的具體信息
指定訪問的請求方法
當(dāng)然curl默認(rèn)使用GET方式訪問。使用了 -d, --data <data> 選項(xiàng),那么會(huì)默認(rèn)為 POST方法訪問。如果此時(shí)還想實(shí)現(xiàn) GET 訪問,那么可以使用 -G, --get 選項(xiàng)強(qiáng)制curl 使用GET方法訪問。
同時(shí) -X, --request <command> 選項(xiàng)也可以指定訪問方法。
POST請求和數(shù)據(jù)傳輸
為了抓包查看信息所以使用了 --local-port <num>[-num] 選項(xiàng),在實(shí)際應(yīng)用中不需要該選項(xiàng)。
[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
保存訪問網(wǎng)頁
使用linux的重定向功能保存
curl www.baidu.com >> baidu.html
使用curl的大O選項(xiàng)
通過 -O, --remote-name 選項(xiàng)實(shí)現(xiàn)。
[root@iZ28xbsfvc4Z 20190712]# curl -O https://www.baidu.com # 使用了 -O 選項(xiàng),必須指定到具體的文件 錯(cuò)誤使用
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 選項(xiàng),必須指定到具體的文件 正確使用
% 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選項(xiàng)
通過 -o, --output <file> 選項(xiàng)實(shí)現(xiàn)。
[root@iZ28xbsfvc4Z 20190713]# curl -o sina.txt https://www.sina.com.cn/ # 單個(gè)操作
[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 的地址需要用引號(hào)括起來
[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
允許不安全訪問
當(dāng)我們使用curl進(jìn)行https訪問訪問時(shí),如果SSL證書是我們自簽發(fā)的證書,那么這個(gè)時(shí)候需要使用 -k, --insecure 選項(xiàng),允許不安全的訪問。
[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/ # 允許執(zhí)行不安全的證書連接
<!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響應(yīng)狀態(tài)碼
在腳本中,這是很常見的測試網(wǎng)站是否正常的用法。
通過 -w, --write-out <format> 選項(xiàng)實(shí)現(xiàn)。
[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服務(wù)器以及其端口
很多時(shí)候上網(wǎng)需要用到代理服務(wù)器(比如是使用代理服務(wù)器上網(wǎng)或者因?yàn)槭褂胏url別人網(wǎng)站而被別人屏蔽IP地址的時(shí)候),幸運(yùn)的是curl通過使用 -x, --proxy <[protocol://][user:password@]proxyhost[:port]> 選項(xiàng)來支持設(shè)置代理。
curl -x 192.168.100.100:1080 https://www.baidu.com
模仿瀏覽器訪問
有些網(wǎng)站需要使用特定的瀏覽器去訪問他們,有些還需要使用某些特定的瀏覽器版本。我們可以通過 -A, --user-agent <agent string> 或者 -H, --header <header> 選項(xiàng)實(shí)現(xiàn)模擬瀏覽器訪問。
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(盜鏈)
有些網(wǎng)站的網(wǎng)頁對http訪問的鏈接來源做了訪問限制,這些限制幾乎都是通過referer來實(shí)現(xiàn)的。
比如:要求是先訪問首頁,然后再訪問首頁中的郵箱頁面,這時(shí)訪問郵箱的referer地址就是訪問首頁成功后的頁面地址。如果服務(wù)器發(fā)現(xiàn)對郵箱頁面訪問的referer地址不是首頁的地址,就斷定那是個(gè)盜連了。
可以通過 -e, --referer 或則 -H, --header <header> 實(shí)現(xiàn)偽造 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/
構(gòu)造HTTP請求頭
可以通過 -H, --header <header> 實(shí)現(xiàn)構(gòu)造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/
保存響應(yīng)頭信息
可以通過 -D, --dump-header <file> 選項(xiàng)實(shí)現(xiàn)。
[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 # 生成的頭文件
限時(shí)訪問
--connect-timeout <seconds> 連接服務(wù)端的超時(shí)時(shí)間。這只限制了連接階段,一旦curl連接了此選項(xiàng)就不再使用了。
# 當(dāng)前 https://www.zhangXX.com 是國外服務(wù)器,訪問受限
[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> 允許整個(gè)操作花費(fèi)的最大時(shí)間(以秒為單位)。這對于防止由于網(wǎng)絡(luò)或鏈接變慢而導(dǎo)致批處理作業(yè)掛起數(shù)小時(shí)非常有用。
[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
顯示抓取錯(cuò)誤
當(dāng)我們請求訪問失敗時(shí)或者沒有該網(wǎng)頁時(shí),網(wǎng)站一般都會(huì)給出一個(gè)錯(cuò)誤的提示頁面。
如果我們不需要這個(gè)錯(cuò)誤頁面,只想得到簡潔的錯(cuò)誤信息。那么可以通過 -f, --fail 選項(xiàng)實(shí)現(xiàn)。
[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 # 得到更簡潔的錯(cuò)誤信息
curl: (22) The requested URL returned error: 404 Not Found
表單登錄與cookie使用
參見「Linux curl 表單登錄或提交與cookie使用」:http://www.zhangblog.com/2019/07/20/curl03/
文件上傳與下載
涉及 FTP 服務(wù),簡單快速搭建可參考:《CentOS7下安裝FTP服務(wù)》「https://www.cnblogs.com/zhi-leaf/p/5983550.html」
文件下載網(wǎng)頁文件下載
# 以進(jìn)度條展示,而不是進(jìn)度表展示
[root@iZ28xbsfvc4Z 20190715]# curl -# -o tmp.data2 http://www.zhangblog.com/uploads/tmp/tmp.data
######################################################################## 100.0%
FTP文件下載
說明1:其中 ftp1 用戶是ftp服務(wù)端的賬號(hào),具體家目錄是:/mnt/ftp1
說明2:當(dāng)我們使用 curl 通過 FTP 進(jìn)行下載時(shí),后面跟的路徑都是:當(dāng)前使用的 ftp 賬號(hào)家目錄為基礎(chǔ)的相對路徑,然后找到的目標(biāo)文件。
示例1
# 其中 tmp.data 的絕對路徑是:/mnt/ftp1/tmpdata/tmp.data ;ftp1 賬號(hào)的家目錄是:/mnt/ftp1
# 說明:/tmpdata/tmp.data 這個(gè)路徑是針對 ftp1 賬號(hào)的家目錄而言的
[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 賬號(hào)的家目錄是:/mnt/ftp1
# 說明:/../../tmp/nginx-1.14.2.tar.gz 這個(gè)路徑是針對 ftp1 賬號(hào)的家目錄而言的
[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> 選項(xiàng)實(shí)現(xiàn)。
說明1:其中 ftp1 用戶是ftp服務(wù)端的賬號(hào),具體家目錄是:/mnt/ftp1
# 其中 tmp_client.data 是客戶端本地文件;
# /tmpdata/ 這個(gè)路徑是針對 ftp1 賬號(hào)的家目錄而言的,且上傳時(shí)該目錄必須是存在的,否則上傳失敗。
# 因此上傳后文件在ftp服務(wù)端的絕對路徑是:/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
斷點(diǎn)續(xù)傳
使用 -C, --continue-at <offset> 選項(xiàng)實(shí)現(xiàn)。其中使用 “-C -”「注意有空格和無空格的情況」,告訴curl自動(dòng)找出在哪里/如何恢復(fù)傳輸。
網(wǎng)頁端斷點(diǎn)續(xù)傳下載
curl -C - -o tmp.data http://www.zhangblog.com/uploads/tmp/tmp.data # 下載一個(gè) 2G 的文件
FTP斷點(diǎn)續(xù)傳下載
細(xì)節(jié)就不多說了,可參見上面的「FTP文件下載」
curl -C - -o tmp.data1 ftp://ftp1:123456@172.16.1.195:21/tmpdata/tmp.data # 下載一個(gè) 2G 的文件
# 或則
curl -C - -o tmp.data1 -u ftp1:123456 ftp://172.16.1.195:21/tmpdata/tmp.data # 下載一個(gè) 2G 的文件
分段下載
有時(shí)文件比較大,或者難以迅速傳輸,而利用分段傳輸,可以實(shí)現(xiàn)穩(wěn)定、高效并且有保障的傳輸,更具有實(shí)用性,同時(shí)容易對差錯(cuò)文件進(jìn)行更正。
可使用 -r, --range <range> 選項(xiàng)實(shí)現(xiàn)。
如下示例使用了同一張圖片,大小為 18196 字節(jié)。
網(wǎng)頁端分段下載分段下載
[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
### 分段下載一個(gè)文件
[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」的原創(chuàng)文章,版權(quán)歸作者所有,如需轉(zhuǎn)載請聯(lián)系作者。
原文:https://blog.csdn.net/woshizhangliang999/article/details/98946071
【End】
*請認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。