最新消息

[公告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
curllinux下指令)
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內容敘述有錯,歡迎糾正,謝謝。

參考資料:
其他相關