最新消息

[公告2014/05/30] 如有需要將部落格中,任何一篇文章的程式碼使用在商業用途,請與我聯繫。

[公告2015/04/26] Line版的 iInfo程式與投資應用 群組已上線想加入的朋友們,請先查看 "入群須知" 再與我聯繫 Line : aminwhite5168,加入請告知身分與回答 "入群須知" 的問題。

[公告2018/04/22] 台北 Python + Excel VBA 金融資訊爬蟲課程,課程如網頁內容 金融資訊爬蟲班:台北班 Python 金融資訊爬蟲、EXCEL VBA 金融資訊爬蟲。

[公告2019/01/08] 請注意:我再次重申,部落格文章的程式碼,是要提供各位參考與學習,一旦網頁改版請自行修改,別要求東要求西要我主動修改,你們用我寫東西賺錢了、交差了,請問有分我一杯羹嗎?既然賺錢沒分我,請問有什麼理由要求我修改,如果沒能力改,就花錢來找我上課。

[公告2019/12/01] 若各位有 Excel VBA 案子開發需求,歡迎與我聯繫,可接案處理。

[公告2020/05/22] 頁面載入速度慢,起因為部分JS來源(alexgorbatchev.com)失效導致頁面載入變慢,目前已做調整,請多見諒。

2015年10月28日 星期三

網路爬蟲系列 (Crawler)(4):Get與Post觀念介紹

原本要寫有關Context-Type的說明,追到後面看到很多有關Get與Post內容乾脆也寫一篇Get與Post差異來糾正並說明一些觀念。
在 W3C RFC 2616 中說明 HTTP/1.1規範中共有8種方法來以不同方式操作指定的資源。
  • GET
  • POST
  • PUT
  • DELETE
  • HEAD
  • OPTIONS
  • TRACE
  • CONNECT
  • PATCH
上述前4種為最基本且最常被提及的方法,GET、POST、PUT、DELETE 這4種方法主要的行為動作就是對網路資源進行 查、改、增、刪 4個操作,這樣的說明應該有初步的了解,如果還不是很清楚,就讓我們繼續看下去。

1. 根據HTTP/1.1規範,Get用於資訊獲取,而且應該是安全的、冪等的。
  • 所謂安全的意味著該操作用於獲取資訊而非修改資訊。換句話說,Get請求一般不應產生副作用。就是說,它僅僅是獲取資源資訊,就像資料庫查詢一樣,不會修改或增加資料,不會影響資源的狀態。(注意:這裡安全的含義僅僅是指是非修改資訊。)
  • 冪等(idempotent)的意味著對同一URL的多個請求應該返回同樣的結果。根據 HTTP 規格,Gst、Head、Put 和 Delete 是 idempotent,相同的 Request 再執行一次,結果還是一樣。
2. 根據HTTP/1.1規範,Post表示可能修改變服務器上的資源的請求。
  • 這裡說的改變,包括增加、修改和刪除。
  • Post不是冪等。
以上是 HTTP 協議中的要求,眾多瀏覽器和瀏覽器插件都遵守這些約定。如果你的程式碼不按照這約定來,可能會出現嚴重的後果。

以下將以 HTTP/1.1規範內容、收集資料, 將Get與Post做比較列表,讓大家比較有感覺:

項目
Get
Post
主要用途
用於與伺服器獲取/查詢資源資訊
用於向伺服器傳送、變更資源資訊
資料傳送量
數據傳輸量小
由於數據放在URL裡傳遞給服務器處理,資料傳送長度受限於URL。註1
傳送大量資料
由於不透過 URL帶參數,所以不受限於URL長度。
支援字元集與編碼註2
使用7位元的ASCII註3
支援ISO10646字元集
預設使用ISO 8859-1編碼(ISO 8859-1包括了ASCII)
傳送安全性
低
表單參數與寫內容可在URL看到。
高
透過 HTTP Request 方式,參數與填寫內容不會顯示於URL。
資料傳送前後網址變化
網址會帶有表單的參數與資料。
網址不會改變。
傳輸方式
在Request-URI中傳輸
(在URL中傳輸)
在Request-URI傳輸
(為隱藏傳輸)
傳送
用戶端用QueryString傳送數據註4
用戶端用Message-Body傳送Form的數據註5
冪等方法註6
是
否
是否被Cache註7
是
否
傳輸安全性
差
好
執行效率
好
差
其他
預設傳輸方法


註1. 各家瀏覽器URL使用長度限制如下。
瀏覽器
最大長度(字元數)
備註
Internet Explorer
2,083
如果超過這個數位,提交按鈕沒有任何反應
Firefox
65,536
chrome
8,182
Safari
80,000
Opera
190,000
curl(linux下指令)
8,167

註2. 請參考 關於URL編碼。

註3. 請參考 C/C++中文問題探討。

註4. Querystring(查詢字串)是附加在網頁URL結尾的資訊。主要是在Url上傳遞資料,可能是一個搜尋字串、頁碼、某項特定的指標…或類似的東西,在網址結尾加上一個問號 ( ? ) 開始,每一組參數都是用「&」區隔開來,是一種Key / Value的組合。

註5. 請參考 RFC 2188: Returning Values from Forms: multipart/form-data,這份文件說明了在 HTTP POST 訊息中使用多種格式訊息的作法。

註6. 冪等觀念延伸數學定義而來,有興趣可參考維基。簡單說就是使用相同方法、參數,對同一網址列進行多次資料存取,其伺服器接收與回傳的資料內容都不會新增改變。

註7. Cache為PC系統中用來紀錄被使用過或參考過的資源位置,當該資源需要再度被使用時,可直接透過Cache中的紀錄直接使用,主要是用來加速資料的存取,一般在CPU中都有Cache來做為系統存取加速使用。同樣觀念套用至瀏覽器上,只要透過URL存取過的網站,都會被記錄於瀏覽器的Cache上。

筆者這用以下段程式碼的執行結果來搭配說明Get的Post差異:
Test.php
<?php
//以下php內容為Server端處理資料
header("Content-Type:text/html; charset=big5");

//從Server取得Get、Post或其他方法傳送進來的資料
$method = $_SERVER['REQUEST_METHOD'];

//判別資料來源類型做轉換,確認是否有資料存在
switch ($method){
 case 'GET':
  $parameters = $_GET;
  break;
 case 'POST':
  $parameters = $_POST;
  break;
}
//isset判別網頁剛開啟時,未傳進參數時會出現"Notice: Undefined index"這樣的警告
//處理方法 http://alfredwebdesign.blogspot.tw/2013/05/php-notice-undefined-index.html
$acc = isset($parameters['Acc'])? $parameters['Acc'] : 0; //帳號
$pwd = isset($parameters['Pwd'])? $parameters['Pwd'] : 0; //密碼
$hid = isset($parameters['Hid'])? $parameters['Hid'] : 0; //隱藏內容,為網頁常見的使用方法

$isAllNull = empty($acc) && empty($pwd) && empty($test) ; 
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <title>Form method : Get與Post測試</title>    
    <meta http-equiv="Content-Type" content="text/html; charset=Big5">
    
    <!--以下JavaScript內容為Client端處理--> 
    <script language="JavaScript">
    //設定表單使用Post傳送內容
    function PostInfo(Formname, action, method)
    {    
      var f = document.forms[Formname];
      f.action = action;
      f.method = method;
      f.submit();
      return true;
    }
    
    //寫入內容到DIV或SPAN
    function WriteOnScreen()
    {
      var info;                             
      info =  "帳號 : " + document.getElementById("Acc").value + "<br/ >";
      info = info + "密碼 : " + document.getElementById("Pwd").value + "<br/ >";
      info = info + "隱藏 : " + document.getElementById("Hide").value; 
      document.getElementById("screen").innerHTML = info;
    }           
    </script>
    <body>
      <!--以下HTML內容為Client端處理--> 
      <form id="Form01" name="myForm" action="Test.php" method="">
        帳號 : <input type="text" name="Acc" id="Acc" size="14" /> <br/ >
        密碼 : <input type="password" name="Pwd" id="Pwd" size="14" /> <br/ >
        <input type="hidden" name="Hid" id="Hide" value='Test'/>
        <input type="submit" value="使用Get傳送表單資料" /><br/ >  
        <input type="button" value="使用Post傳送表單資料" onclick="PostInfo('myForm', 'Test.php', 'POST');" /><br/ > 
        <input type="button" value="直接抓取" onclick="WriteOnScreen();" /> 
      </form>   
      <?php
      //以下php內容為Server端處理資料
      if(!$isAllNull){
       echo $method;
       echo '<br/ >';
       echo '================<br/ >';
       echo '帳號 : '.$acc.' <br/ >'; 
       echo '密碼 : '.$pwd.' <br/ >'; 
       echo '隱藏 : '.$hid.' <br/ >';
       echo '================<br/ >';
      }
      ?>
      <div id ="screen" > </div>
    </body>
</html>  
以上程式碼感謝Line群裡的清權大大協助完成。

執行以上程式碼需要php的環境,若是為了要執行以上程式碼要大家安裝去Apache 與php,將是一件大工程,筆者這裡推薦一個簡易版的伺服器系統:Usbwebserver,大家可以去官網下載無須安裝、操作簡易、容易擴充、方便使用、檔案大小約82 MB一個隨身碟即可帶著走,使用教學。

我們來看看程式碼執行Get與Post表單時,如何去傳送資料給Server,各位可以再對照上面列表的內容,就會看的出來兩者之間的差異。
Get傳送

如上圖,Get傳送資料從Client至Server
1. 透過瀏覽器的URL進行傳送。
2. 資料若為非ASCII,會將其編碼後再行傳送。
3. 將資料以Query String形式進行傳送。

Post傳送

如上圖,Post傳送資料從Client至Server
1. 不透過URL傳送,以Form Data形式進行傳送。
2. 資料若為非ASCII,會將其編碼後再行傳送。
3. Content-type若無指定,將以application/x-www-form-urlencoded為預設傳輸。


觀念糾正:

1. HTTP/1.1規範中,Method(Get、Post)和Data(URL, Body, Header)是正交(獨立)的兩個概念,也就是說,使用哪個Method與應用層的資料如何傳輸是沒有相互關係。

2. HTTP/1.1規範沒有要求,如果Method是Post資料就要放在Body中。也沒有要求,如果Method是Get,資料(參數)就一定要放在URL中而不能放在Cache中。

3. 由於Cache的基準是以URL為對象,如果傳遞的參數不同時,很難發現cache的存在,因為Cache內容沒有新紀錄。

4. HTTP/1.1規範,如果伺服端指定適當的Cache-Control或Expires標頭,仍可以對POST的回應進行快取。

5. HTTP/1.1規範 中並沒有特定限制Get或Post資料傳送的長度限制,但實際各個Web伺服器會規定對Post提交數據大小進行限制,Apache、IIS6都有各自的配置。

6. 大家誤解的資料傳輸的方法只有Get與Post,原因如下
  • 現在對於表單傳送大多僅介紹Get與Post。
  • 網頁工程師可能對於其他方法不熟悉。
  • 對於網路資源的操作可透過Get、Post做 查、改、增、刪 的功能,不需用到Put和Delete。
基於以上內容,請大家注意資料傳輸的方式不是僅限於Get與Post。


其他補充內容:

1. Post:請求參數是在http標題的一個不同部分(名為entity body)傳輸的,這一部分用來傳輸表單信息,因此必須將Content-type設置為:application/x-www-form-urlencoded。Post設計用來支持web窗體上的用戶字段,其參數也是作為key/value對傳輸。
       但是:它不支持複雜數據類型,因為Post沒有定義傳輸數據結構的語義和規則。

2. soap:是http post的一個專用版本,遵循一種特殊的xml消息格式
       Content-type設置為: text/xml任何數據都可以xml化

如以上關於Get與Post內容敘述有錯,歡迎糾正,謝謝。

參考資料:
其他相關