1. 程式人生 > >[Java網路安全系列面試題] GET 和 POST 的區別在哪裡?

[Java網路安全系列面試題] GET 和 POST 的區別在哪裡?

![[Java網路安全系列面試題] GET 和 POST 的區別在哪裡?](https://upload-images.jianshu.io/upload_images/7326374-e991dc90ec15060b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ## 一. 概述 本文的內容源自其他部落格的總結,屬於筆者的讀書筆記,結構如下: - HTTP 的請求報文 - GET 方法的特點 - POST 方法的特點 - GET 和 POST 的區別 ## 二. HTTP 的請求報文 首先我們要解決的第一個問題是:GET 和 POST 是什麼? > GET 和 POST 其實都是 HTTP 的請求方法。除了這 2 個請求方法之外,HTTP 還有 **HEAD** 、**PUT** 、**DELETE**、**TRACE**、**CONNECT**、**OPTIONS** 這 6 個請求方法。所以HTTP 的請求方法共計有 8 種,它們的描述如下所示: 表格資料來源:菜鳥教程 |請求方法|描述| | ---- | ---- | |GET |請求指定的頁面資訊,並返回實體主體。| |POST |向指定資源提交資料進行處理請求(例如提交表單或者上傳檔案)。資料被包含在請求體中。POST請求可能會導致新的資源的建立和/或已有資源的修改。| |HEAD| 類似於get請求,只不過返回的響應中沒有具體的內容,用於獲取報頭。| |PUT |從客戶端向伺服器傳送的資料取代指定的文件的內容。| |DELETE |請求伺服器刪除指定的頁面。| |TRACE |回顯伺服器收到的請求,主要用於測試或診斷。| |CONNECT |HTTP/1.1協議中預留給能夠將連線改為管道方式的代理伺服器。| |OPTIONS |允許客戶端檢視伺服器的效能。| 接下來我們解決第二個問題:請求方法如何使用? 要解決這個問題,我們首先需要了解 HTTP 的請求報文結構: ![HTTP 的請求報文結構](https://upload-images.jianshu.io/upload_images/7326374-269cd0469541c158.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 可以看到 HTTP 的請求報文由三部分構成: - **請求行**:由請求方法(Method)、URL 欄位和 HTTP 的協議版本組成,注意其中的空格、回車符和換行符均不可省略,所以我們的請求方法實際上就是位於請求行中的了。 - **請求頭部**:位於請求行之後,個數可以為 0~若干個,每個請求頭部都包含一個頭部欄位名和一個值,它們之間用冒號 ":" 分隔,在最後用回車符和換行符表示結束。 - **請求資料**:如果請求方法為 **GET**,那麼請求資料為空。它主要是在 **POST** 中進行使用,適用於需要填表單(FORM)的場景。 我們通過一個實際的例子來看看 **HTTP** 的 **GET** 請求報文是什麼樣的,我們這裡以訪問 `https://api.github.com/search/users?q=JakeWharton` 為例,通過抓包我們得到的請求報文如下所示: ``` GET /search/users?q=JakeWharton HTTP/1.1 Host: api.github.com Connection: keep-alive Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Cookie: _octo=GH1.1.1623908978.1549006668; _ga=GA1.2.548087391.1549006688; logged_in=yes; dotcom_user=GoMarck; _gid=GA1.2.17634150.1554639136; _gat=1 ``` 我們重點看到請求行: ``` GET /search/users?q=JakeWharton HTTP/1.1 ``` 可以看到請求方法用的是 **GET **請求,**URL**為` /search/users?q=JakeWharton`,協議為 **HTTP1.1**。 請求行下面部分全都是請求頭部,我們可以看到 **host** 為 `api.github.com`,連線方式為長連線等資訊。值得注意的是我們這個例子中是不存在請求資料的。 接下來我們在來看一下 **POST** 請求的報文(該例子源自其他部落格): ``` POST / HTTP/1.1 Host: www.wrox.com User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 Content-Type: application/x-www-form-urlencoded Content-Length: 40 Connection: Keep-Alive name=Professional%20Ajax&publisher=Wiley ``` 可以看到請求行中請求方法為 **POST**,**URL** 為空,協議版本也是 **HTTP1.1** 。它和上面 **GET** 方法例子不一樣的地方在於它的請求引數是位於請求資料中的,可以看到 name=Professional%20Ajax&publisher=Wiley 就是它的請求資料。並且我們要注意到在請求資料和請求頭之間是空出一行的,這是必不可少的。 ## 三. GET 方法的特點 1. 前面的例子:`https://api.github.com/search/users?q=JakeWharton` 就是一個非常典型的 **GET **請求的表現形式,即請求的資料會附在 **URL** 之後(放在請求行中),以 **?** 分割 **URL** 和傳輸資料,多個引數用 **&** 連線。 2. 除此之外,根據 **HTTP** 規範,**GET** 用於資訊獲取,而且應該是安全和冪等的 。 >**安全性**: 指的是非修改資訊,即該操作用於獲取資訊而非修改資訊。換句話說,**GET** 請求一般不應產生副作用,也就是說,它僅僅是獲取資源資訊,就像資料庫查詢一樣,不會修改,增加資料,不會影響資源的狀態。 >**冪等性**(Idempotence): 則指的是無論呼叫這個**URL** 多少次,都不會有不同的結果的 **HTTP** 方法。而在實際過程中,這個規定沒有那麼嚴格。例如在一個新聞應用中,新聞站點的頭版不斷更新,雖然第二次請求會返回不同的一批新聞,該操作仍然被認為是安全的和冪等的,因為它總是返回當前的新聞。 3. **GET** 是會被瀏覽器主動快取的,如果下一次傳輸的資料相同,那麼就會返回快取中的內容,以求更快地展示資料。 4. **GET** 方法的 **URL** 一般都具有長度限制,但是需要注意的是 **HTTP** 協議中並未規定 **GET** 請求的長度。 這個長度限制主要是由瀏覽器和 Web 伺服器所決定的,並且各個瀏覽器對長度的限制也各不相同 。 5. **GET** 方法只產生一個 **TCP** 資料包,瀏覽器會把請求頭和請求資料一併傳送出去,伺服器響應 200 ok(返回資料)。 ## 四. POST 方法的特點 1. 根據 **HTTP** 規範,**POST** 表示可能修改變伺服器上的資源的請求。例如我們在刷知乎的時候對某篇文章進行點贊,就是提交的 **POST** 請求,因為它改變了伺服器中的資料(該篇文章的點贊數)。 2. **POST** 方法因為有可能修改伺服器上的資源,所以它是不符合安全和冪等性的。 3. 從前面關於 **POST** 的請求報文也可以看出,**POST** 是將請求資訊放置在請求資料中的,這也是 **POST** 和 **GET** 的一點不那麼重要的區別。有一些部落格的說法是 **GET** 請求的請求資訊是放置在 **URL** 的而 **POST** 是放置在請求資料中的所以 **POST** 比 **GET** 更安全。其實這種說法很有問題,隨便抓下包 **POST** 中的請求報文就暴露無疑了,這又何來安全之說? 4. 因為 **POST** 方法的請求資訊是放置在請求資料中的,所以它的請求資訊是沒有長度限制的。 5. **POST** 方法會產生兩個 **TCP** 資料包,瀏覽器會先將請求頭髮送給伺服器,待伺服器響應`100 continue`,瀏覽器再發送請求資料,伺服器響應`200 ok`(返回資料)。這麼看起來 **GET** 請求的傳輸會比 **POST** 快上一些(因為**GET** 方法只發送一個 **TCP** 資料包),但是實際上在網路良好的情況下它們的傳輸速度基本相同。 ## 五. GET 和 POST 的區別 上面說了那麼多 **GET** 方法和 **POST** 方法各自的特點,它們在外在的表現上似乎是有著諸多的不同,但是實際上,**它們的本質是一樣的,並無區別**!!! 這似乎有些不可思議,但是我們重新回想一下 **GET** 和 **POST** 是什麼?它們是 **HTTP** 請求協議的請求方法,而 **HTTP** 又是基於**TCP/IP**的關於資料如何在全球資訊網中如何通訊的協議,所以 **GET/POST** 實際上都是 **TCP** 連結。 也就是說,**GET** 和 **POST** 所做的事其實是一樣的,如果你給 **GET** 加上請求資料,給 **POST** 加上 **URL** 引數,這在技術上是完全可行的,事實上確實有一些人為了貪圖方便在更新資源時用了**GET**,因為用**POST**必須要到**FORM**(表單),這樣會麻煩一點(**但是強烈不建議這樣子做**!!!)。 **既然 GET 和 POST 的底層都是 TCP,那麼為什麼 HTTP 還要特別將它們區分出來呢?** 其實可以想象一下,如果我們直接使用 TCP 進行資料的傳輸,那麼無論是單純獲取資源的請求還是修改伺服器資源的請求在外觀上看起來都是 TCP 連結,這樣就非常不利於進行管理。所以在 HTTP 協議中,就會對這些不同的請求設定不同的類別進行管理,例如單純獲取資源的請求就規定為 GET、修改伺服器資源的請求就規定為 POST,並且也對它們的請求報文的格式做出了相應的要求(例如請求引數 GET 位於 URL 而 POST 則位於請求資料中)。 當然,如果我們想將 GET 的請求引數放置在請求資料中或者將 POST 的請求資料放置在 URL 中,這是完全可以的,雖然這樣子做並不符合 HTTP 的規範。但是這樣子做是否能得到我們期望的響應資料呢?答案是未必,這取決於伺服器的行為。 以 GET 方法在請求資料中放置請求引數為例,有些伺服器會將請求資料中的引數讀出,在這種情況下我們依然能獲得我們期望的響應資料;而有些伺服器則會選擇直接忽略,這種情況下我們就無法獲取期望的響應資料了。 所以,對於 GET 和 POST 的區別,總結來說就是:**它們的本質都是 TCP 連結,並無區別。但是由於 HTTP 的規定以及瀏覽器/伺服器的限制,導致它們在應用過程中可能會有所不同。** ## 推薦 * [400道——大廠Java選擇題](https://mp.weixin.qq.com/s?__biz=MzIwMTg3NzYyOA==&mid=2247484198&idx=1&sn=9c9d8c2dffe005e0cf76f13af815209a&chksm=96e67235a191fb235caac777b002e2b0b519a4d540341352518a3c6939c03f164adb1cd3d659&token=1610544259&lang=zh_CN#rd) * [[Java網路系列面試題]常見web攻擊有哪些?](https://mp.weixin.qq.com/s?__biz=MzIwMTg3NzYyOA==&mid=2247484207&idx=1&sn=72bc31c8b141013fdb3ba4cf77c20326&chksm=96e6723ca191fb2a5f17a9918b006b6b3d4341d166c4aaf497ad2d7bcff2d4ef03b4e40bd4dd&token=1394220820&lang=zh_CN#rd) * [HR面試都會問什麼問題(下)](https://mp.weixin.qq.com/s?__biz=MzIwMTg3NzYyOA==&mid=2247483919&idx=1&sn=f4a2caf39f739015cad4c80d89755b7f&chksm=96e6731ca191fa0a390d17ada5a20209991362a72952ca7d4de70982ec3f399e458fdeeab822&token=981501366&lang=zh_CN#rd) ## 文末 >歡迎關注個人微信公眾號:**Coder程式設計** 歡迎關注**Coder程式設計**公眾號,主要分享資料結構與演算法、Java相關知識體系、框架知識及原理、Spring全家桶、微服務專案實戰、DevOps實踐之路、每日一篇網際網路大廠面試或筆試題以及PMP專案管理知識等。更多精彩內容正在路上~ 新建了一個qq群:315211365,歡迎大家進群交流一起學習。謝謝了!也可以介紹給身邊有需要的朋友。 >文章收錄至 Github: https://github.com/CoderMerlin/coder-programming Gitee: https://gitee.com/573059382/coder-programming 歡迎**關注**並star~ ![微信公眾號](https://upload-images.jianshu.io/upload_images/7326374-f34fe8227b81d3e9?imageMogr2/auto-orient/strip%7CimageView2/2