關於http協議GET和POST方法的區別我們可以從各處得到比較一致的答案,今天我們來填一個面試中可能碰到的一個坑。
當面試官問你“你覺得GET和POST有什么區別"時,我們可能會想到以下幾點(來源於網絡):
- GET在瀏覽器回退時是無害的,而POST會再次提交請求。
- GET產生的URL地址可以被Bookmark,而POST不可以。
- GET請求會被瀏覽器主動cache,而POST不會,除非手動設置。
- GET請求只能進行url編碼,而POST支持多種編碼方式。
- GET請求參數會被完整保留在瀏覽器歷史記錄里,而POST中的參數不會被保留。
- 對參數的數據類型,GET只接受ASCII字符,而POST沒有限制。
- GET比POST更不安全,因為參數直接暴露在URL上,所以不能用來傳遞敏感信息。
- GET參數通過URL傳遞,POST放在Request body中。
- GET請求在URL中傳送的參數是有長度限制的,而POST么有。
以上答案除了最后2條基本沒什么問題,我們現在測試一下到底什么情況。
在HTTP協議中並沒有明確論述不同的請求方法使用的傳送數據方式(url,body)不同,所以我們假設沒有這種區別。
我們實現一個的socket server 端程序進行測試
package main import ( "fmt" "log" "net" ) func main() { l, err := net.Listen("tcp", ":8080") if err != nil { log.Fatalln("err:", err) } defer l.Close() for { c, err := l.Accept() if err != nil { log.Fatalln("err:", err) } go process(c) } } func process(c net.Conn) { defer func() { c.Close() if err := recover(); err != nil { log.Println("process error:", err) } }() rH := `HTTP/1.1 200 OK Content-Type:"application/json"` rSegmentation := "\r\n\r\n" rB := `{"data":"success"}` resp := rH + rSegmentation + rB bs := make([]byte, 1024) // 讀請求 n, _ := c.Read(bs) fmt.Println(string(bs[:n])) // 響應 c.Write([]byte(resp)) }
GET方法通過url傳遞數據如下
server接收到的http請求
GET方法通過body傳遞數據如下
server接收到的請求
POST方法通過url傳遞數據
server接收到的請求
POST方法通過body傳遞數據
server接收到的請求
上述四種測試case均成功,所以“GET參數通過URL傳遞,POST放在Request body中”和“GET請求在URL中傳送的參數是有長度限制的,而POST么有”是錯誤的。具體來說:
- 無論POST還是GET方法,傳遞數據(參數)既可通過URL也可以通過body
- POST或者GET方法如果通過body傳遞數據(參數)是沒有長度限制的
- POST或者GET方法通過URL傳遞數據理論上也沒有長度限制(因為url存在於http協議的header部分,而http header並沒有長度限制)
- 通常所說的參數數據限制是指瀏覽器或者werbserver會的一種設定,假如自己實現client和server完全能做到不限制長度
所以從協議角度來看GET和POST本質上並沒有區別.