由於 HTTP request 不規範導致的被防火牆攔截
- 2019 年 11 月 27 日
- 筆記
一段程式在本地調試正常後,放到網上卻時斷時續,最後確認問題如下
1. HTTP request 中的 Host: 段是 HTTP 1.1 規範,在 1.0 中沒有這個
2. 但是目前通常環境中(我用的 Ubuntu,不過其他發行版應該也有這問題),PHP 中的一些函數如 file_get_contents 會發送錯誤的 request
例如只是這麼簡單的一行
- file_get_contents ( 'http://www.163.com' );
發送的頭兩行是
GET / HTTP/1.0 Host: www.163.com
3. 有些防火牆會把這些不規範的 HTTP 通訊攔截掉:就算你用的機器沒設置 iptable,通常機房本身都會有硬體防火牆的
昨天出現問題,是沒料想到 PECL OAuth 也是如此
Update in 2010.12.31
王博 對這個問題做了補充
1.在他的 CentOS 5.3 上,PECL OAuth 默認用的 HTTP 1.1
2. OAuth::setRequestEngine 方法可以提供 OAUTH_REQENGINE_STREAMS 和 OAUTH_REQENGINE_CURL 兩種不同方式,後者就可以避免上述問題了。
解決方法有很多種,不過為了程式碼最大適應性(就像為什麼現在大家都不用短標籤 <? 一樣),我覺得不要使用 file_get_contents 獲取遠程數據(在該函數的官方頁評論里,你會看到各種各樣的相同功能的 封裝 ) 、棄用 PECL OAuth 比較好,雖然隨著時間的流逝這個問題最終會被修正
編譯也可以解決,我在虛擬機了編譯了份 ./configure –disable-all –with-curl –with-curlwrappers ,確認發的是 HTTP 1.1 了,但 with-curlwrappers 參數的解釋是 EXPERIMENTAL : Use cURL for url streams
第一次見如何用 tcpdump,在調試這個問題時,可以用
sudo tcpdump -A host www.163.com and 'tcp[20:4] = 0x47455420'
前者是監聽的域名,「and」後面的大概可以理解為條件 substr($line, 20, 4) == pack('H*', '47455420')