原文:https://www.fanhaobai.com/2017/08/curl-expect-continue.html
curl 在項目中使用頻率較高,比如內部接口、第三方 api、圖片存儲服務等,但是我們在使用 curl 時可能并沒有注意到 Expect 這個請求頭信息,而 Expect 設置不正確,會導致不必要的一次 HTTP 請求,甚至可能會導致業務邏輯錯誤。
問題
在不設置 Expect 頭信息使用 curl 發送 POST 請求時,如果 POST 數據大于 1kb,curl 默認行為 如下:
- 先追加一個
Expect: 100-continue
請求頭信息,發送這個不包含 POST 數據的請求; - 如果服務器返回的響應頭信息中包含
Expect: 100-continue
,則表示 Server 愿意接受數據,這時才 POST 真正數據給 Server;
通過 tcpdump 工具抓包 curl 客戶端網絡請求。查看 HTTP 請求響應頭以及數據:
$ tcpdump -A -s 0 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'
請求信息內容:
23:04:15.498902 IP bogon.35808 > 10.16.**.***.http: Flags [P.], seq 1749154338:1749154696, ack 673671676, win 14600, length 358
E.....@.@.8...U.
......PhA."('i.P.9.]Q..POST /* HTTP/1.1
User-Agent: GuzzleHttp/6.2.1 curl/7.19.7
Content-Type: application/json
Host: *.t.ziroom.com
Content-Length: 24343
Expect: 100-continue
響應信息:
23:04:15.499869 IP 10.16.**.***.http > bogon.35808: Flags [P.], seq 1:26, ack 358, win 64240, length 25
E..A......2.
.....U..P..('i.hA..P.......HTTP/1.1 100 Continue
可見此時,curl 發送了一次不必要的 HTTP 請求,從系統性能上來說這是不允許的。另外,并不是所有的 Server 都會正確響應100-continue
,反而會返回417 Expectation Failed
,curl 端不會發起數據 POST 請求,則會造成業務邏輯錯誤,我們應該避免這種情況的發生。
解決辦法
如果查看過一些開源類庫(guzzle、qq第三方api,不過 solarium 并未支持),你就會發現他們在 curl 時已經注意到并解決這個問題了,只需 設置 Expect 請求頭為空 即可。
// qq第三方api
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
// guzzle的curl Adapter
if (!$request->hasHeader('Expect')) {
$conf[CURLOPT_HTTPHEADER][] = 'Expect:';
}
再次 tcpdump 抓包,發現使用 curl 發送超過 1kb 的 POST 數據時,也并未出現 100-continue 的 HTTP 請求。