考慮以下情境:你使用Terminal Service登入遠端主機,基於資安限制,不能安裝軟體,無法傳送檔案到該主機,也該無法連線網際網路,唯一可用的瀏覽器只有IE6(喵的,IE6根本不算瀏覽器吧?),而你必須測試以HTTP POST存取某個API是否正常?

這像不像一宗密室殺人案件?看似所有可行做法都已被封殺,正等待金田一或柯南說出一個有點扯又有點巧妙的殺人計劃… 但,這是我親身遭遇的難題!(補聲暗)

仔細想想,情況並不如想像糟,雖然不能裝工具、沒有Chrome/POSTMan可用,還是可以寫VBScript/JavaScript操作XmlHttpRequest執行測試。只是平日都由jQuery或Angular代勞,對XHR語法不熟,還要查範例寫程式有點麻煩,直接用工具還是方便。靈機一動想到好方法-用Telnet模擬HTTP POST Request!

用Telnet測試問題主機的80埠,是我診斷網站問題常用的技巧之一。例如:發現用瀏覽器開啟網頁無回應,我會退一步試試Telnet web_server_ip 80,輸入GET /page_path按Enter,等同發出HTTP GET Request存取httq://web_server_ip/page_path,如果伺服器有回應內容,便代表問題出在瀏覽器,可能被設了無效的Proxy之類的。

以下是簡單示範,用Telnet讀取style.css:(注意:Telnet 80 Port連線成功後,鍵盤輸入的字元不會顯示出來,在以下操作中,輸入內容為"GET /MVC4/content/style.css",最後按Enter)

不過,這招測試.css、.js、.html等靜態資源OK,存取.aspx或MVC等動態程式卻常會失效,原因是網站伺服器對HTTP Request有更多要求,還需要額外Request Header。例如:若試著輸入GET /MVC4/Home/Index存取HomeController的Index() Action,會得到HTTP 400錯誤:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Bad Request</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Bad Request - Invalid Verb</h2>
<hr><p>HTTP Error 400. The request verb is invalid.</p>
</BODY></HTML>

原因是伺服器僅接受HTTP 1.1要求,我們在GET命令後方加上"HTTP/1.1"改成GET /MVC4/Home/Index HTTP/1.1。測試結果不同,但仍會出錯:

HTTP/1.1 400 Bad Request
Content-Type: text/html; charset=us-ascii
Server: Microsoft-HTTPAPI/2.0
Date: Tue, 10 Mar 2015 22:44:18 GMT
Connection: close
Content-Length: 334

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Bad Request</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Bad Request - Invalid Hostname</h2>
<hr><p>HTTP Error 400. The request hostname is invalid.</p>
</BODY></HTML>

錯誤訊息指出少了Hostname Header,我們充實Request內容再送一次,總算成功了:(註:HomeController.Inext()以return Content("Test OK")傳回單一字串)

依經驗,一個HTTP 1.1 GET Request起碼包含以下內容:

GET /MVC4/Home/Index HTTP/1.1
Host: localhost
Connection: close

網站伺服器需要"Host: URL使用的主機名稱"判斷該將Request交給哪一個Web站台處理(同一IP同樣80 Port,依Host名稱可連至不同Web站台);而HTTP 1.1預設使用Keep-Alive,指定Connection: close要求送完回應後主動斷線,可省去自己按Ctrl-C中止Telnet程式的步驟。

同理,只要組合適當的Request內容,要模擬POST送表單也不是難事。憑空拼湊Request Header太累,較簡便的做法是在其他機器用瀏覽器送一次,再經由F12工具找出送出內容。以Chrome為例,在Network找到Request封包,Request Headers有個「view source」按鈕:

展開後可以看到完整的Request Headers內容,有些非必要性如Cookie或User-Agent的可以省略,稍加調整就是要的測試內容:

如此,我們就能用Telnet模擬各式HTTP Request囉~


Comments

# by Jace Ju

雖然文章中提到沒辦法安裝任何工具,但如果可以用 cURL 的話會更方便,不用自己輸入一堆 header 指令: http://evelynnote.blogspot.tw/2011/03/curl.html 它也有 Windows 版本: http://goo.gl/Wb0rH3

# by Jeffrey

to Jace Ju, 感謝分享,cUrl很威!(已筆記)

Post a comment


78 - 28 =