常常遇到「既然GET請求能夠作POST請求的事情,爲何還要區分GET和POST而不僅使用一個請求?」的問題。做爲在實際中被使用最廣的兩個請求方法,這個問題其實挺難回答的,但萬物總有其根由,今天就追根究底。html
查看RFC規範再加上以前查過的一些二手文章,整理了以下的觀點:chrome
GET 被強制服務器支持瀏覽器
瀏覽器對URL的長度有限制,因此GET請求不能代替POST請求發送大量數據緩存
GET請求發送數據更小安全
GET請求是安全的服務器
GET請求是冪等的app
POST請求不能被緩存koa
POST請求相對GET請求是「安全」的ide
All general-purpose servers MUST support the methods GET and HEAD. All other methods are OPTIONAL.post
GET 一般用於請求服務器發送某個資源。在HTTP/1.1中,要求服務器實現此方法;POST請求方法起初是用來向服務器輸入數據的。在HTTP/1.1中,POST方法是可選被實現的,沒有明確規定要求服務器實現。
RFC 2616 (Hypertext Transfer Protocol — HTTP/1.1) states in section 3.2.1 that there is no limit to the length of an URI (URI is the official term for what most people call a URL)
RFC 2616 中明確對 uri 的長度並無限制。不過雖然在RFC中並無對uri的長度進行限制,可是各大瀏覽器廠家在實現的時候限制了URL的長度,可查到的是IE對長度限制爲2083;而chrome遇到長度很長的URL時,會直接崩潰。
因此這條結論算是正確的。
只能經過寫代碼驗證了:下面第一個文件是服務器代碼,做用是在客戶端發送GET和POST請求的時候返回200狀態碼。第二個文件是客戶端HTML文件,點擊兩個button,分別發送GET請求和POST請求。
import koa from 'koa' import fs from 'mz/fs' const app = koa() app.use(function* (next) { if(this.path == '/test') return this.status = 200 yield next }) app.use(function* (next) { this.type = 'html' this.body = yield fs.readFile('./index.html') yield next }) app.listen(8080) console.log('koa server port: 8080')
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <button id="get">GET</button> <button id="post">POST</button> </body> <script> function http(type) { return function (url) { var req = new XMLHttpRequest() req.open(type, url) req.send() } } var getDom = document.getElementById('get') , postDom = document.getElementById('post') , get = http('GET') , post = http('POST') getDom.addEventListener('click', function () { get('/test') }) postDom.addEventListener('click', function () { post('/test') }) </script> </html>
從上兩張圖能夠看到POST請求的headers要比GET請求多了兩個屬性。因此這條結論其實也算是對的,不過從請求發送時間來看的話,其實二者並無差異。
Of the request methods defined by this specification, the GET, HEAD,OPTIONS, and TRACE methods are defined to be safe.
這裏的安全指的是在規範的定義下,Get操做不會修改服務器的數據
A request method is considered "idempotent" if the intended effect on
the server of multiple identical requests with that method is the
same as the effect for a single such request. Of the request methods
defined by this specification, PUT, DELETE, and safe request methods
are idempotent.
從上面能夠看到GET請求是安全的,在冪等性中說PUT和DELETE以及安全method都是冪等的,因此GET天然也被包括了。
咱們在實際使用過程當中對HTTP請求的優化大多數都放在GET請求上,好比對沒有數據變化的請求(網站中經常使用的靜態文件)作緩存,在潛意識中認爲只有GET請求才能夠被緩存,因此歷來也不會考慮POST請求的緩存優化,然而在RFC中提到GET和POST以及HEAD都是能夠被緩存的。不過不要驚訝,以前不知道POST能夠被緩存是由於標準也很無奈,瀏覽器的實現老是比標準厲害。
In general, safe methods thatdo not depend on a current or authoritative response are defined as cacheable; this specification defines GET, HEAD, and POST as cacheable, although the overwhelming majority of cache implementations only support GET and HEAD.
這一點不少人都會質疑,被抓包以後的POST請求和GET請求是同樣裸露的,因此更安全的說法是不對的。我這裏全部的「安全」是相對的,由於GET請求有時候會直接反應在瀏覽器的地址欄,而如今的瀏覽器大多會記住曾經輸入過的URL。試想若是你曾經在別人電腦上填過一個很私密的表單,那麼你的這份記錄極可能被連沒什麼電腦常識的人都一覽無遺。