都 9102 年了,還問 GET 和 POST 的區別

2021-02-19 前端大全

(給前端大全加星標,提升前端技能)

作者:程淇銘

https://segmentfault.com/a/1190000018129846

1 前言

最近看了一些同學的面經,發現無論什麼技術崗位,還是會問到 get 和 post 的區別,而搜索出來的答案並不能讓我們裝得一手好逼,那就讓我們從 HTTP 報文的角度來擼一波,從而搞明白他們的區別。

2 標準答案

在開擼之前嗎,讓我們先看一下標準答案長什麼樣子 w3school: GET 對比 POST。標準答案很美好,但是在面試的時候把下面的表格甩面試官一臉,估計會裝逼不成反被*。

分類GETPOST後退按鈕/刷新無害數據會被重新提交(瀏覽器應該告知用戶數據會被重新提交)。書籤可收藏為書籤不可收藏為書籤緩存能被緩存不能緩存編碼類型application/x-www-form-urlencodedapplication/x-www-form-urlencoded 或 multipart/form-data。為二進位數據使用多重編碼。歷史參數保留在瀏覽器歷史中。參數不會保存在瀏覽器歷史中。對數據長度的限制是的。當發送數據時,GET 方法向 URL 添加數據;URL 的長度是受限制的(URL 的最大長度是 2048 個字符)。無限制。對數據類型的限制只允許 ASCII 字符。沒有限制。也允許二進位數據。安全性與 POST 相比,GET 的安全性較差,因為所發送的數據是 URL 的一部分。在發送密碼或其他敏感信息時絕不要使用 GET !POST 比 GET 更安全,因為參數不會被保存在瀏覽器歷史或 web 伺服器日誌中。可見性數據在 URL 中對所有人都是可見的。數據不會顯示在 URL 中。

注意,並不是說標準答案有誤,上述區別在大部分瀏覽器上是存在的,因為這些瀏覽器實現了 HTTP 標準。但是,前面列舉的只是瀏覽器實現上的區別,而不是 get 和 post 的本質區別。

3 GET 和 POST 報文上的區別

先下結論,GET 和 POST 方法沒有實質區別,只是報文格式不同。

GET 和 POST 只是 HTTP 協議中兩種請求方式,而 HTTP 協議是基於 TCP/IP 的應用層協議,無論 GET 還是 POST,用的都是同一個傳輸層協議,所以在傳輸上,沒有區別。

報文格式上,不帶參數時,最大區別就是第一行方法名不同

POST方法請求報文第一行是這樣的 POST /uri HTTP/1.1 \r\n

GET方法請求報文第一行是這樣的 GET /uri HTTP/1.1 \r\n

是的,不帶參數時他們的區別就僅僅是報文的前幾個字符不同而已

帶參數時報文的區別呢? 在約定中,GET 方法的參數應該放在 url 中,POST 方法參數應該放在 body 中

舉個例子,如果參數是 name=chengqm, age=22。

GET 方法簡約版報文是這樣的

GET /index.php?name=qiming.c&age=22 HTTP/1.1

Host: localhost

POST 方法簡約版報文是這樣的

POST /index.php HTTP/1.1

Host: localhost

Content-Type: application/x-www-form-urlencoded

name=qiming.c&age=22

現在我們知道了兩種方法本質上是 TCP 連接,沒有差別,也就是說,如果我不按規範來也是可以的。我們可以在 URL 上寫參數,然後方法使用 POST;也可以在 Body 寫參數,然後方法使用 GET。當然,這需要服務端支持。

4. 常見問題GET 方法參數寫法是固定的嗎?

在約定中,我們的參數是寫在 ? 後面,用 & 分割。

我們知道,解析報文的過程是通過獲取 TCP 數據,用正則等工具從數據中獲取 Header 和 Body,從而提取參數。

也就是說,我們可以自己約定參數的寫法,只要服務端能夠解釋出來就行,一種比較流行的寫法是 http://www.example.com/user/name/chengqm/age/22。

POST 方法比 GET 方法安全?

按照網上大部分文章的解釋,POST 比 GET 安全,因為數據在地址欄上不可見。

然而,從傳輸的角度來說,他們都是不安全的,因為 HTTP 在網絡上是明文傳輸的,只要在網絡節點上捉包,就能完整地獲取數據報文。

要想安全傳輸,就只有加密,也就是 HTTPS。

GET 方法的長度限制是怎麼回事?

在網上看到很多關於兩者區別的文章都有這一條,提到瀏覽器地址欄輸入的參數是有限的。

首先說明一點,HTTP 協議沒有 Body 和 URL 的長度限制,對 URL 限制的大多是瀏覽器和伺服器的原因。

瀏覽器原因就不說了,伺服器是因為處理長 URL 要消耗比較多的資源,為了性能和安全(防止惡意構造長 URL 來攻擊)考慮,會給 URL 長度加限制。

POST 方法會產生兩個TCP數據包?

有些文章中提到,post 會將 header 和 body 分開發送,先發送 header,服務端返回 100 狀態碼再發送 body。

HTTP 協議中沒有明確說明 POST 會產生兩個 TCP 數據包,而且實際測試(Chrome)發現,header 和 body 不會分開發送。

所以,header 和 body 分開發送是部分瀏覽器或框架的請求方法,不屬於 post 必然行為。

5 talk is cheap show me the code

如果對 get 和 post 報文區別有疑惑,直接起一個 Socket 服務端,然後封裝簡單的 HTTP 處理方法,直接觀察和處理 HTTP 報文,就能一目了然

#!/usr/bin/env python

# -*- coding: utf-8 -*-

import socket

HOST, PORT = '', 23333

def server_run():

   listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

   listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

   listen_socket.bind((HOST, PORT))

   listen_socket.listen(1)

   print('Serving HTTP on port %s ...' % PORT)

   while True:

       # 接受連接

       client_connection, client_address = listen_socket.accept()

       handle_request(client_connection)

def handle_request(client_connection):

   # 獲取請求報文

   request = ''

   while True:

       recv_data = client_connection.recv(2400)

       recv_data = recv_data.decode()

       request += recv_data

       if len(recv_data) < 2400:

           break

   # 解析首行

   first_line_array = request.split('\r\n')[0].split(' ')

   # 分離 header 和 body

   space_line_index = request.index('\r\n\r\n')

   header = request[0: space_line_index]

   body = request[space_line_index + 4:]

   # 列印請求報文

   print(request)

   # 返回報文

   http_response = b"""\

HTTP/1.1 200 OK

<!DOCTYPE html>

<html>

<head>

   <title>Hello, World!</title>

</head>

<body>

<p style="color: green">Hello, World!</p>

</body>

</html>

"""

   client_connection.sendall(http_response)

   client_connection.close()

if __name__ == '__main__':

   server_run()

上面代碼就是簡單的列印請求報文然後返回 HelloWorld 的 html 頁面,我們運行起來

[root@chengqm shell]# python httpserver.py

Serving HTTP on port 23333 ...

然後從瀏覽器中請求看看

列印出來的報文

然後就可以手動證明上述說法,比如說要測試 header 和 body 是否分開傳輸,由於代碼沒有返回 100 狀態碼,如果我們 post 請求成功就說明是一起傳輸的(Chrome/postman)。

又比如 w3school 裡面說 URL 的最大長度是 2048 個字符,那我們在代碼裡面加上一句計算 uri 長度的代碼

...

# 解析首行

first_line_array = request.split('\r\n')[0].split(' ')

print('uri長度: %s' % len(first_line_array[1]))

...

我們用 postman 直接發送超過 2048 個字符的請求看看

然後我們可以得出結論,url 長度限制是某些瀏覽器和伺服器的限制,和 HTTP 協議沒有關係。

到此,我們可以愉快地裝逼了 :)

參考:

99%的人都理解錯了HTTP中GET與POST的區別

關於HTTP GET 和 POST

w3school: HTTP 方法:GET 對比 POST

wikipedia: 超文本傳輸協議

RFC 2068

END

覺得本文對你有幫助?請分享給更多人

關注「前端大全」加星標,提升前端技能

喜歡就點一下「好看」唄~

相關焦點

  • 必須知道的get和post的區別
    get、post常見的區別get和post不同點的誤區附錄常見的http狀態碼1.什麼是http這裡只是簡單概述一下,更多詳情可以參見:基於tcp/ip、一種網絡應用層協議、超文本傳輸協議HyperText Transfer
  • 我終於知道post和get的區別
    此話一出,不知激起了多少(碼農)程式設計師的憤怒,卻又無可奈何,於是碼農問程式設計師。碼農:你知道get和post請求到底有什麼區別?程式設計師:你看這篇就知道了。碼農:你月薪三萬了?程式設計師:嗯。碼農:你是怎麼做到的?
  • Get 和 Post 區別
    瀏覽器的get和post有什麼區別?第1個從他們字面意思去理解這些,就是從網頁上獲取一個數據。然後這個獲取數據是對伺服器不會產生副作用的,術語就是數學上的 冪等即多次操作不產生影響(比如任何數乘1或者乘0,多次乘之後,都不會變化),那樣多次操作也不會去產生副作用。
  • 程式設計師:我終於知道post和get的區別
    此話一出,不知激起了多少(碼農)程式設計師的憤怒,卻又無可奈何,於是碼農問程式設計師。碼農:你知道get和post請求到底有什麼區別?程式設計師:你看這篇就知道了。碼農:你月薪三萬了?程式設計師:嗯。碼農:你是怎麼做到的?
  • 美團面試官,一上來,就叫我說Post和Get的區別?我慌了...
    此話一出,不知激起了多少(碼農)程式設計師的憤怒,卻又無可奈何,於是碼農問程式設計師。碼農:你知道get和post請求到底有什麼區別?程式設計師:你看這篇就知道了。碼農:你月薪三萬了?程式設計師:嗯。碼農:你是怎麼做到的?
  • jQuery的$.get()、$.post()和$.ajax()以GET/POST方式請求數據
    、post、put、deletet等,但是最常用的是獲取數據和提交數據,獲取數據是get請求,提交數據是post請求。GET請求時,Url地址是暴露出來的,大家都可以看,且還可以收藏起來以便下次使用。HTTP POST請求:一般情況下是指將本地的數據提交到遠程的伺服器上去處理和存儲。POST請求時,URL地址是隱藏起來的,不能被收藏。
  • 問題回答:Http 請求的Post 和Put 的區別
    群友不知道哪裡找來的通俗解釋大家對這個問題看法各異,查到的資料也都不一樣。那麼到底Http 請求的 post 和 put的區別是什麼呢?特別提一下,我們不能把一些中文資料裡的通俗解釋當作標準答案。首先,這裡有一個誤區,很多沒寫過 web 應用的同學認為這兩個方法的功能區別是固有的,一定存在的。但實際上, http 請求的 post 和 put分別具體實現什麼樣的功能,都是由程式設計師在寫服務端代碼時決定的。
  • php獲取web伺服器數據的快捷方法:post和get的區別與聯繫
    但是,在人人都離不開網際網路的時代,你知道網際網路是如何通過代碼獲取web伺服器上的數據嗎?下面,就來聊聊網際網路獲取數據的常用方法——get和post方法。這兩種方法都可以獲取web伺服器上的數據。不過,他們既有相同點,也有不同點。下面我們一起來看看這兩種方法的詳細情況吧。
  • HTTP|GET 和 POST 區別?
    這和網上流傳的說法一致。但是這只是HTML標準對HTTP協議的用法的約定。怎麼能當成GET和POST的區別呢?而且,現代的Web Server都是支持GET中包含BODY這樣的請求。雖然這種請求不可能從瀏覽器發出,但是現在的Web Server又不是只給瀏覽器用,已經完全地超出了HTML伺服器的範疇了。
  • 面試官:說一下 GET 和 POST 的區別?
    」本質上都是TCP連結,並無差別但是由於HTTP的規定和瀏覽器/伺服器的限制,導致他們在應用過程中會體現出一些區別二、區別從w3schools得到的標準答案的區別如下:GET在瀏覽器回退時是無害的,而POST會再次提交請求
  • 接口測試實戰| GET/POST 請求區別詳解
    在日常的工作當中,HTTP 請求中使用最多的就是 GET 和 POST 這兩種請求方式。
  • 網絡爬蟲——Requests,GET和POST
    Requests繼承了urllib的所有特性,Requests支持http連結保持和連接池,支持使用cookie保持會話,支持文件上傳,支持自動確定響應內容的編碼,支持國際化的url和post數據自動編碼。Requests的底層實現其實就是urllib3.
  • PHP面試題:put與post的區別
    不知道存在put這種方式http協議規定了四種資源訪問形式:get、post、put、delete。get:獲取資源 post:修改資源 put:上傳資源 delete:刪除資源 在html的form表單的method裡只有get與post兩種方式2.
  • $.get與$.post高級實現
    jQuery.get(url,[data],[callback],[type]) :Ajax中的get請求 jQuery.post(url,[data],[callback],[type]) :Ajax中的post請求
  • 表單FORM與GET方法的區別
    表單提交中Get和Post方式的區別有5點1. get是從伺服器上獲取數據,post是向伺服器傳送數據。2. get是把參數數據隊列加到提交表單的ACTION屬性所指的URL中,值和表單內各個欄位一一對應,在URL中可以看到。
  • curl模擬delete/put/post/get請求curl模擬delete/put/post/get請求
    一般http 的請求有delete/put/post/get 幾種請求方式,delete 用於刪除請求,可以理解為刪除/修改/添加/查詢 但是這只是規範的寫法
  • PHP:6種GET和POST請求發送方法
    博客中,我試過了暢言和多說兩種社會化評論框,後來還是拋棄了暢言,不安全。無論是暢言還是多說,我都需要從遠程抓取文章的評論數,然後存入本地資料庫。1、用file_get_contents 以get方式獲取內容:<?php$url='http://www.shiyanlou.com/';$html = file_get_contents($url);echo $html;?
  • 9102年是什麼意思 誇張了時間的久遠
    9102年是什麼意思 誇張了時間的久遠時間:2019-03-31 17:16   來源:德榮科技   責任編輯:凌君 川北在線核心提示:原標題:9102年是什麼意思 誇張了時間的久遠 德榮科技 這段時間很多人在抖音和微博的評論中看到一個關於9102年的梗,這個梗出現的時候很多人都是丈二和尚摸不著頭腦,因為現在明明是
  • WEB前端開發工程師可以了解的PHP基礎表單提交GET/POST
    /*管理員登陸1.前臺頁面 :用戶名 密碼 登陸放在form中1.2.用戶輸入可以提交: 提交到那個頁面action 提交方式 method=get post 默認提交參數方式是get1.3.確定提交參數 加上name
  • 公司規定所有接口都用 POST請求,這是為什麼?
    今天再次看到這個問題,我也有了一些新的理解和感觸,臨時回顧了一下 get 與 post 的請求的一些區別:post更安全(不會作為url的一部分,不會被緩存、保存在伺服器日誌、以及瀏覽器瀏覽記錄中)post能發送更多的數據類型(get只能發送ASCII字符)post用於修改和寫入數據,get一般用於搜索排序和篩選之類的操作get請求的是靜態資源