由於 HTTP request 不規範導致的被防火牆攔截

  • 2019 年 11 月 27 日
  • 筆記

一段程式在本地調試正常後,放到網上卻時斷時續,最後確認問題如下

1. HTTP request 中的 Host: 段是 HTTP 1.1 規範,在 1.0 中沒有這個

2. 但是目前通常環境中(我用的 Ubuntu,不過其他發行版應該也有這問題),PHP 中的一些函數如 file_get_contents 會發送錯誤的 request

例如只是這麼簡單的一行

  1. 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')