淺談HTTP中GET、POST用法以及它們的區別

淺談HTTP中GET、POST用法以及它們的區別
  • GET方法;
  • POST方法;
  • PUT方法;
  • DELETE方法。
  • HEAD方法;
  • TRACE方法;
  • OPTIONS方法;

  1. Get是最經常使用的方法,一般用於請求服務器發送某個資源,並且應該是安全的和冪等的。php

    (1). 所謂安全是指該操做用於獲取信息而非修改信息。換句話說,GET 請求通常不該產生反作用。就是說,它僅僅是獲取資源信息,就像數據庫查詢同樣,不會修改和增長數據,不會影響資源的狀態。 html

      注意:這裏安全的含義僅僅是指是非修改信息。數據庫

    (2). 冪等是指對同一個URL的多個請求應該返回一樣的結果。這裏我再解釋一下冪等這個概念:api

    冪等(idempotent、idempotence)是一個數學或計算機學概念,常見於抽象代數中。 
    冪等有如下幾種定義: 
      對於單目運算,若是一個運算對於在範圍內的全部的一個數屢次進行該運算所得的結果和進行一次該運算所得的結果是同樣的,那麼咱們就稱該運算是冪等的。好比絕對值運算就是一個例子,在實數集中,有abs(a)=abs(abs(a))。 
      對於雙目運算,則要求當參與運算的兩個值是等值的狀況下,若是知足運算結果與參與運算的兩個值相等,則稱該運算冪等,如求兩個數的最大值的函數,在實數集中即是冪等的 ,即max(x,x) = x。瀏覽器

  2. POST方法向服務器提交數據,好比完成表單數據的提交,將數據提交給服務器處理。緩存

  3. PUT方法是讓服務器用請求的主體部分來建立一個由所請求的URL命名的新文檔;若是那個文檔存在的話,就用這個主體來代替它。安全

  4. DELETE方法就是請求服務器刪除指定URL所對應的資源。可是,客戶端沒法保證刪除操做必定會被執行,由於HTTP規範容許服務器在不通知客戶端的狀況下撤銷請求。服務器

  5. HEAD方法與GET方法的行爲很相似,但服務器在響應中只返回實體的主體部分。這就容許客戶端在未獲取實際資源的狀況下,對資源的首部進行檢查,markdown

    使用HEAD,咱們能夠更高效的完成如下工做: 
    ①. 在不獲取資源的狀況下,瞭解資源的一些信息,好比資源類型; 
    ②. 經過查看響應中的狀態碼,能夠肯定資源是否存在; 
    ③. 經過查看首部,測試資源是否被修改。網絡

  6. TRACE方法會在目的服務器端發起一個「迴環」診斷,咱們都知道,客戶端在發起一個請求時,這個請求可能要穿過防火牆、代理、網關、或者其它的一些應用程序。這中間的每一個節點均可能會修改原始的HTTP請求,TRACE方法容許客戶端在最終將請求發送服務器時,它變成了什麼樣子。因爲有一個「迴環」診斷,在請求最終到達服務器時,服務器會彈回一條TRACE響應,並在響應主體中攜帶它收到的原始請求報文的最終模樣。這樣客戶端就能夠查看HTTP請求報文在發送的途中,是否被修改過了。

  7. OPTIONS方法用於獲取當前URL所支持的方法。若請求成功,則它會在HTTP頭中包含一個名爲「Allow」的頭,值是所支持的方法,如「GET, POST」。


GET和POST的區別:

  1. GET請求的數據會附在URL以後(就是把數據放置在HTTP協議頭中),以?分割URL和傳輸數據,參數之間以&相連,如:login.action?name=hyddd&password=idontknow&verify=%E4%BD%A0%E5%A5%BD。若是數據是英文字母或數字,則原樣發送;若是是空格,轉換爲+;若是是中文或其餘字符,則直接把字符串用BASE64加密,得出如:%E4%BD%A0%E5%A5%BD,其中%XX中的XX爲該符號以16進製表示的ASCII碼值。而與之對應的,POST把提交的數據放置在HTTP包的包體中,文章最下面將會有代碼示例。

  2. POST的安全性要比GET的安全性高。注意:這裏所說的安全性和上面GET提到的「安全」不是同個概念。上面「安全」的含義僅僅是不做數據修改,而這裏安全的含義是真正的Security的含義。好比:經過GET提交數據,用戶名和密碼將明文出如今URL上,由於:(1)登陸頁面有可能被瀏覽器緩存,(2)其餘人查看瀏覽器的歷史紀錄,那麼別人就能夠拿到你的帳號和密碼了,除此以外,使用GET提交數據還可能會形成Cross-site request forgery攻擊(CSRF,跨站請求僞造,也被稱爲:one click attack/session riding)。

例:銀行網站A,它以GET請求來完成銀行轉帳的操做,如:http://www.mybank.com/Transfer.php?toBankId=11&money=1000 
危險網站B,它裏面有一段HTML的代碼以下:< img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000/>

首先,你登陸了銀行網站A,而後訪問危險網站B,噢,這時你會發現你的銀行帳戶少了1000塊…… 
爲何會這樣呢?緣由是銀行網站A違反了HTTP規範,使用GET請求更新資源。在訪問危險網站B以前,你已經登陸了銀行網站A,而B中的< img …/>以GET的方式請求第三方資源(這裏的第三方就是指銀行網站A了。本來這是一個合法的請求,但這裏被不法分子利用了),因此你的瀏覽器會帶上你的銀行網站A的Cookie發出Get請求,去獲取資源「http://www.mybank.com/Transfer.php?toBankId=11&money=1000」,結果銀行網站服務器收到請求後,認爲這是一個更新資源操做(轉帳操做),因此就馬上進行轉帳操做…… 
爲了杜絕上面的問題,銀行改用POST請求完成轉帳操做。


GET和POST的誤區: 
誤區一:POST能夠比GET提交更多更長的數據?

因爲使用GET方法提交數據時,數據會以&符號做爲分隔符的形式,在URL後面添加須要提交的參數,有人會說,瀏覽器地址欄輸入的參數是有限的,而POST不用再地址欄輸入,因此POST就比GET能夠提交更多的數據。難道真的是這樣的麼?

而實際上,URL不存在參數上限的問題,HTTP協議規範沒有對URL長度進行限制。這個限制是特定的瀏覽器及服務器對它的限制。IE對URL長度的限制是2083字節(2K+35)。對於其餘瀏覽器,如Netscape、FireFox等,理論上沒有長度限制,其限制取決於操做系統的支持。因此POST也是沒有大小長度限制的,HTTP協議規範也沒有進行大小限制。起限制做用的是服務器的處理能力。總歸一句話,這個限制是針對全部HTTP請求的,與GET、POST沒有多少關係。


注意: 
上面大概說了一下HTTP規範中GET和POST的一些原理性的問題。但在實際的作的時候,不少人卻沒有按照HTTP規範去作,致使這個問題的緣由有不少,好比說:

  1. 不少人貪方便,更新資源時用了GET,由於用POST必需要用到FORM(表單),這樣會麻煩一點。

  2. 對資源的增,刪,改,查操做,其實均可以經過GET/POST完成,不須要用到PUT和DELETE。

  3. 早期的Web MVC框架設計者們並無有意識地將URL看成抽象的資源來看待和設計,因此致使一個比較嚴重的問題是傳統的Web MVC框架基本上都只支持GET和POST兩種HTTP方法,而不支持PUT和DELETE方法。

  4. 你們都以爲使用GET很方便,畢竟使用POST要用到Form。可是使用GET方法時,瀏覽器會緩存你的地址等信息,留下歷史記錄和Cookie。而對於POST方法,則不會進行緩存。之後在開發中,必定要分清楚GET和POST的使用場合 


建立和更新某個URL表明的資源的時候,是用HTTP的PUT仍是POST:

摘抄自:http://www.cnblogs.com/shanyou/archive/2011/10/17/2215930.html

其實,用PUT仍是POST,不是看這是建立仍是更新資源的動做,這不是風格的問題,而是語義的問題。REST是一種風格,可是仍是依賴於HTTP協議。在HTTP中,PUT被定義爲idempotent的方法,POST則不是,這是一個很重要的區別。

「Methods can also have the property of 「idempotence」 in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request.」

上面的話就是說,若是一個方法重複執行屢次,產生的效果是同樣的,那就是idempotent的。

舉一個簡單的例子,假如由一個博客系統提供一個Web API,模式是 http://superblogging/blogs/post/{blog-name} 。很簡單,將{blog-name}替換爲咱們的blog名字,往這個URI發送一個HTTP PUT或者POST請求,HTTP的body部分就是博文,這是一個很簡單的REST API例子。咱們應該用PUT方法仍是POST方法?取決於這個REST服務的行爲是不是idempotent的,假如咱們發送兩個http://superblogging/blogs/post/Sample請求,服務器端是什麼樣的行爲?若是產生了兩個博客帖子,那就說明這個服務不是idempotent的,由於屢次使用產生了反作用;若是後一個請求把第一個請求覆蓋掉了,那這個服務就是idempotent的。前一種狀況,應該使用POST方法,後一種狀況,應該使用PUT方法。

也許你會以爲這兩個方法的差異沒什麼大不了的,用錯了也不會有什麼問題,可是你的服務一放到internet上,若是不聽從HTTP協議的規範,就可能給本身帶來麻煩。好比,沒準Google Crawler也會訪問你的服務,若是讓一個不是indempotent的服務能夠用indempotent的方法訪問,那麼你服務器的狀態可能就會被Crawler修改,這是不該該發生的。


使用GET:

@Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new AsyncTask<String, Void, Void>() { //網絡加載是耗時操做,放在異步任務中 @Override protected Void doInBackground(String... params) { //至關於線程中的run方法,執行後臺操做 try { URL u = new URL(params[0]); URLConnection conn = u.openConnection(); //獲取URL的互聯網鏈接 InputStream is = conn.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); //包裹到BufferedReader中 String line; while ((line = br.readLine()) != null) { System.out.println(line); } br.close(); isr.close(); is.close(); } catch (IOException e) { e.printStackTrace(); } return null; } }.execute("http://apis.juhe.cn/oil/region?key=3f73d0ea9d7c33d288fdc16f5257c1a5&format=2&city=%E5%8C%97%E4%BA%AC%E5%B8%82"); //execte(URL)使用GET方法時,填入的URL是帶有信息的,例子中使用的是聚合數據提供的加油站數據 }

 

 

使用POST:

@Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new AsyncTask<String, Void, Void>() { @Override protected Void doInBackground(String... params) { //至關於線程中的run方法,執行後臺操做 try { URL u = new URL(params[0]); HttpURLConnection conn = (HttpURLConnection) u.openConnection(); //使用POST,需將URLConnection轉換成HttpURLConnection //使用以前,須要先對conn進行配置 conn.setDoInput(true); conn.setDoOutput(true); //設置成true,conn才能向服務器輸出數據 conn.setRequestMethod("POST"); //請求方式設置爲POST OutputStreamWriter osw = new OutputStreamWriter(conn.getOutputStream()); //把數據傳到服務器 BufferedWriter bw = new BufferedWriter(osw); bw.write("key=3f73d0ea9d7c33d288fdc16f5257c1a5&format=2&city=%E5%8C%97%E4%BA%AC%E5%B8%82"); //要傳遞的數據 bw.flush(); InputStream is = conn.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String line; while ((line = br.readLine()) != null) { System.out.println(line); } br.close(); isr.close(); is.close(); } catch (IOException e) { e.printStackTrace(); } return null; } }.execute("http://apis.juhe.cn/oil/region"); }

 

上述兩段代碼獲取到的數據結果同樣,以下圖: 
這裏寫圖片描述

從圖片能夠看出,咱們已經成功獲取到數據


本文部份內容轉載自下面的博文,可是原博文的部份內容是不正確的,我對其作了總結和修改。所以讀者在前往原文觀看時,先擦亮眼睛哈,多看看,多瞧瞧。還有,若是我也錯了,請你們必定要指正: 
http://www.jellythink.com/archives/806 
http://www.cnblogs.com/shanyou/archive/2011/10/17/2215930.html 
http://www.cnblogs.com/hyddd/archive/2009/03/31/1426026.html

相關文章
相關標籤/搜索