1. 程式人生 > >http GET 請求 URL 總結

http GET 請求 URL 總結

URL 只能使用英文字母、阿拉伯數字和某些標點符號,不能使用其他文字和符號。網路標準RFC 1738做了硬性規定:

“…Only alphanumerics [0-9a-zA-Z], the special characters “$-_.+!*’(),” [not including the quotes - ed], and reserved characters used for their reserved purposes may be used unencoded within a URL.”

“只有字母和數字[0-9a-zA-Z]、一些特殊符號”$-_.+!*’(),”[不包括雙引號]、以及某些保留字,才可以不經過編碼直接用於URL。”

為什麼需要 URL 編碼

秉承著「知其然還要知其所以然的態度」,先來思考下什麼情況下,我們需要編碼?

  • 這是隱私資料,不是適合明文傳輸
  • 編碼後可以有效的壓縮傳輸的資料量
  • 包含某些會引起歧義的字元

在 URL 中之所以要編碼,就是因為在傳輸的內容跟預留字元(&、=、?)有相同的時候,會造成 URL 伺服器的解析錯誤,比如引數的 key = value 鍵值對中,在 value 中包含 &、=、?等幾種預留字元的時候,你讓伺服器如何解析?

哪些字元需要編碼

保留字

URL 可以劃分成若干元件、協議、主機、路徑等。

  • 一些字元用來分隔不同的元件,比如「:/?#@」
  • 一些字元在每個元件中分隔的,比如 & =

不安全字元

還有些字元,當它們直接放在 URL 中時,可能會引起解釋程式的歧義

  • 空格——URL 在傳輸過程中,使用者排版時,文字處理程式在處理 URL的過程中,都可能引入無關緊要的空格
  • 引號和<>——通常用於在普通文字中起到分隔 URL 的作用
  • # 用於標示書籤或錨點
  • % 本身用作對不安全字元編碼時的特殊字元,所以本身需要編碼
  • {}[]|^ 某些閘道器或者傳輸代理會篡改這些字元

注意

由於歷史原因,目前存在一些不標準的編碼實現,比如對於符號~ 雖然RFC3986文件規定,對於~不需要編碼,但是一些老的閘道器或者傳輸代理會。比如[]也被編碼了。

對於 URL 中的合法字元,編碼和不編碼是等價的,但是對於上面提到的那些字元,如果不編碼,那它們可能會造成 URL 語義的不同。因此,對於 URL 而言,只有普通英文字元和數字、特殊字元和保留字元,能出現在未經編碼的 URL 中,其他字元都需要經過編碼。

編碼規則

先介紹幾種存在的編碼規則,詳細的內容可以看《字元編碼筆記》

  • ASCII 碼: ASCII 碼一共規定 128 個字元編碼(包括 32 個不能列印的控制符號)
  • 非 ASCII 碼:英語 128 個符號編碼是夠的,但用來表示其他語言,128 個符號是不夠的。一些歐洲國家決定利用位元組中閒置的最高位編入新的符號,前 128 位是相同的,後面的 128 位不同
  • unicode:將世界上所有的符號都納入其中,每一個符號都給予一個獨一無二的編碼,消除亂碼問題。Unicode 只是一個符號集,它只規定了符號的二進位制程式碼,卻沒有規定這個二進位制程式碼應該如何儲存。
  • UTF-8: UTF-8 就是在網際網路上使用最廣的一種 Unicode 的實現方式。

如何編碼

URL 編碼通常被稱為百分號編碼(URL Encoding, also know as percent-encoding),因為它的編碼方式很簡單,使用 % 加上兩個字元代表一個位元組的16進位制形式:

URL 編碼預設使用的字符集是 ASCII

  • a 在 ASCII 中對應的位元組是 0x61,經過 URL 編碼後得到就是 %61
  • @ 在 ASCII 中對應的位元組是 0x40,經過 URL 編碼後得到就是 %40
  • 對於非 ASCII 字元,需要使用 ASCII 字符集的超集進行編碼得到相應的字元,然後再對每個字元執行百分號編碼
  • 對於 Unicode 字元,RFC 文件建議使用 UTF-8 對其進行編碼得到相應的位元組,然後再對每個位元組執行百分號編碼

GET vs POST

在被問到 http GET 和 POST 的區別的時候,普遍給出的回答可能是:

  • GET 的引數包含在 URL 中,POST 的引數通過 request body 進行傳遞
  • 在 restful api 規則中, GET 用於從伺服器獲取指定資源,POST 用於在伺服器建立資源;GET 操作是安全的,不管進行多少次操作,資源的狀態都不會改變,POST 操作不是安全的,重複發起多次 POST 的請求,會導致伺服器建立若干資源。

你真的覺得這麼回答就是能拿滿分了嗎?義務教育不是教育過我們不會的時候要多寫點答案,老師還會有個感情分給你,讓我們再想想。

  • GET 在瀏覽器回退的時是無害的,而 POST 會再次提交請求
  • GET 產生的 URL 可以被 Bookmark,而 POST 不可以
  • GET 請求會被瀏覽器主動 cache,而 POST 不會,除非手動設定
  • GET 請求只能進行 URL 編碼(就是上面說的 URL 編碼),而 POST 支援多種編碼方式
  • GET 請求引數會被完整保留在瀏覽器的歷史記錄裡,而 POST 中的引數不會被保留
  • GET 請求在URL 中傳送的引數是有長度限制的,而 POST 沒有
  • 對於引數的資料型別,GET 只接受 ASCII 字元,而 POST 沒有
  • GET 比 POST 更不安全,因為引數直接暴露在 URL 上,所以不能用來傳遞敏感資訊

對於能輕鬆列舉以上不同點的同學,是需要獎勵大紅花的,畢竟筆者也是抄了別人的文章才知道的,不過這還不是最終答案,思考問題更深入一些,它們的底層是不是有什麼不一樣的地方?

我是誰: GET 和 POST 是什麼?

  • HTTP 協議中的兩種傳送請求的方法

我從哪裡來:HTTP 是什麼?

  • HTTP 是基於 TCP/IP 的關於資料如何在全球資訊網中通訊的協議。
  • GET 和 POST 底層都是 TCP 連線, 能做的事情也是相同的。如果你想給 GET 加上 request body, 給 POST 帶上 URL 引數,技術上來說也沒什麼不行的。

99%的人都理解錯了HTTP中GET與POST的區別」中提出了一個很形象的比喻,在你全球資訊網世界中,將 TCP 比喻成汽車用來運輸資料,為了避免送急件的阻塞滿載貨物的汽車,又提出了交通規則 HTTP 。 HTTP 給汽車運輸規定了不同的服務類別,包括 GET、POST、PUT、 DETETE等。瀏覽器可以想象成運輸公司,不同的運輸公司對汽車運輸貨物的量是有要求的,資料量太大對瀏覽器和伺服器都會造成很大負擔。

業界不成文的規定是,(大多數)瀏覽器通常都會限制url長度在2K個位元組,而(大多數)伺服器最多處理64K大小的url。超過的部分,恕不處理。

終極大 boos 來了, GET 和 POST 還有一個很大的不同,簡單的說:

  • GET 產生一個 TCP 資料包,POST 產生兩個 TCP 資料包。
  • 更容易理解的版本:
    • 對於GET方式的請求,瀏覽器會把http header和data一併傳送出去,伺服器響應200(返回資料)
    • 而對於POST,瀏覽器先發送header,伺服器響應100 continue,瀏覽器再發送data,伺服器響應200 ok(返回資料)

參考資料