深刻淺出:5G和HTTP

本文將會講到5G和HTTP。曾經在深刻淺出經典面試題:從瀏覽器中輸入URL到頁面加載發生了什麼 - Part 3 提到爲何有些RPC框架不選用HTTP,而5G會採用HTTP。html

您能夠從本文裏獲取到一些概念:5G用HTTP做爲reference point interface的實現,HTTP/2,RESTful API/HATEOAS/OpenAPI等最佳實踐和標準,這些都是一些常見可是又容易忽略的知識點。java

本文參考了一些文章,見文章末尾的連接列表。git

HTTP的優勢和缺點

咱們你們知道HTTP協議包含的信息太多,太繁重,致使消息體會很大,可是其中有一些消息根本用不上,這也是爲何HTTP/1.1消息效率不高的緣由,因此一些RPC框架捨棄它,例如dubbo定義本身的協議等,若是你們定義過協議,例如相似TCP協議,就能明白協議定義的重要性。若是要效率高,消息短,那就會太底層,如TCP,若是要想易於理解,例如HTTP,那就得長一些。github

5G和HTTP

5G明年試商用,在5G裏採用HTTP協議,確實有意思。能夠參看TS 29.501協議 5G System;Principles and Guidelines for Services Definition,Stage 3。先看看下圖:面試

在通訊領域,由原來的Diameter,AAA等轉變爲HTTP,的確是一個大變化,可是開發的效率將會大大提升。spring

那麼5G將會應用到什麼HTTP相關技術呢?json

  1. HTTP/2/0 (協議下載https://http2.github.io/http2-spec/)
  2. JSON
  3. HATEOAS
  4. RESTful
  5. OpenAPI

HTTP/2.0

仍是先看看HTTP/2吧。談到HTTP/2,最早想到Google的SPDY,它是HTTP/2的前身。爲何Google要作SPDY呢?緣由很簡單,HTTP的效率不高。自從有了SPDY後,加載時間減小64%(http://dev.chromium.org/spdy/spdy-whitepaper),原話這麼說的, In lab tests, we have compared the performance of these applications over HTTP and SPDY, and have observed up to 64% reductions in page load times in SPDY.api

SPDY並不用於取代HTTP,它只是修改了HTTP的請求與應答在網絡上傳輸的方式;這意味着只需增長一個SPDY傳輸層,現有的全部服務端應用均不用作任何修改。 當使用SPDY的方式傳輸,HTTP請求會被處理、標記簡化和壓縮。好比,每個SPDY端點會持續跟蹤每個在以前的請求中已經發送的HTTP報文頭部,從而避免重複發送還未改變的頭部。而還未發送的報文的數據部分將在被壓縮後被髮送。瀏覽器

HTTP/2主要特性包括:服務器

 

二進制協議

HTTP/1.1 版的頭信息確定是文本(ASCII編碼),數據體能夠是文本,也能夠是二進制。HTTP/2 則是一個完全的二進制協議,頭信息和數據體都是二進制,而且統稱爲"幀"(frame):頭信息幀和數據幀。

二進制協議的一個好處是,能夠定義額外的幀。HTTP/2 定義了近十種幀,爲未來的高級應用打好了基礎。若是使用文本實現這種功能,解析數據將會變得很是麻煩,二進制解析則方便得多。

 

多工

HTTP/2 複用TCP鏈接,在一個鏈接裏,客戶端和瀏覽器均可以同時發送多個請求或迴應,並且不用按照順序一一對應,這樣就避免了"隊頭堵塞"。

舉例來講,在一個TCP鏈接裏面,服務器同時收到了A請求和B請求,因而先回應A請求,結果發現處理過程很是耗時,因而就發送A請求已經處理好的部分, 接着迴應B請求,完成後,再發送A請求剩下的部分。

這樣雙向的、實時的通訊,就叫作多工(Multiplexing)。

 

數據流

由於 HTTP/2 的數據包是不按順序發送的,同一個鏈接裏面連續的數據包,可能屬於不一樣的迴應。所以,必需要對數據包作標記,指出它屬於哪一個迴應。

HTTP/2 將每一個請求或迴應的全部數據包,稱爲一個數據流(stream)。每一個數據流都有一個獨一無二的編號。數據包發送的時候,都必須標記數據流ID,用來區分它屬於哪一個數據流。另外還規定,客戶端發出的數據流,ID一概爲奇數,服務器發出的,ID爲偶數。

數據流發送到一半的時候,客戶端和服務器均可以發送信號(RST_STREAM幀),取消這個數據流。1.1版取消數據流的惟一方法,就是關閉TCP鏈接。這就是說,HTTP/2 能夠取消某一次請求,同時保證TCP鏈接還打開着,能夠被其餘請求使用。

客戶端還能夠指定數據流的優先級。優先級越高,服務器就會越早迴應。

 

頭信息壓縮

HTTP 協議不帶有狀態,每次請求都必須附上全部信息。因此,請求的不少字段都是重複的,好比CookieUser Agent,如出一轍的內容,每次請求都必須附帶,這會浪費不少帶寬,也影響速度。

HTTP/2 對這一點作了優化,引入了頭信息壓縮機制(header compression)。一方面,頭信息使用gzipcompress壓縮後再發送;另外一方面,客戶端和服務器同時維護一張頭信息表,全部字段都會存入這個表,生成一個索引號,之後就不發送一樣字段了,只發送索引號,這樣就提升速度了。

 

服務器推送

HTTP/2 容許服務器未經請求,主動向客戶端發送資源,這叫作服務器推送(server push)。

常見場景是客戶端請求一個網頁,這個網頁裏面包含不少靜態資源。正常狀況下,客戶端必須收到網頁後,解析HTML源碼,發現有靜態資源,再發出靜態資源請求。其實,服務器能夠預期到客戶端請求網頁後,極可能會再請求靜態資源,因此就主動把這些靜態資源隨着網頁一塊兒發給客戶端了。 

我給本身挖個坑,後面專門出一篇文章寫HTTP/2.

HATEOAS 約束

HATEOAS(Hypermedia as the engine of application state)是 REST 架構風格中最複雜的約束,也是構建成熟 REST 服務的核心。它的重要性在於打破了客戶端和服務器之間嚴格的契約,使得客戶端能夠更加智能和自適應,而 REST 服務自己的演化和更新也變得更加容易。

在介紹 HATEOAS 以前,先介紹一下 Richardson 提出的 REST 成熟度模型。該模型把 REST 服務按照成熟度劃分紅 4 個層次:(這個能夠參考Richardson的成熟度模型,見後文連接)

  • 第一個層次(Level 0)的 Web 服務只是使用 HTTP 做爲傳輸方式,實際上只是遠程方法調用(RPC)的一種具體形式。SOAP 和 XML-RPC 都屬於此類。
  • 第二個層次(Level 1)的 Web 服務引入了資源的概念。每一個資源有對應的標識符和表達。
  • 第三個層次(Level 2)的 Web 服務使用不一樣的 HTTP 方法來進行不一樣的操做,而且使用 HTTP 狀態碼來表示不一樣的結果。如 HTTP GET 方法來獲取資源,HTTP DELETE 方法來刪除資源。
  • 第四個層次(Level 3)的 Web 服務使用 HATEOAS。在資源的表達中包含了連接信息。客戶端能夠根據連接來發現能夠執行的動做。

從上述 REST 成熟度模型中能夠看到,使用 HATEOAS 的 REST 服務是成熟度最高的,也是推薦的作法。對於不使用 HATEOAS 的 REST 服務,客戶端和服務器的實現之間是緊密耦合的。客戶端須要根據服務器提供的相關文檔來了解所暴露的資源和對應的操做。當服務器發生了變化時,如修改了資源的 URI,客戶端也須要進行相應的修改。而使用 HATEOAS 的 REST 服務中,客戶端能夠經過服務器提供的資源的表達來智能地發現能夠執行的操做。當服務器發生了變化時,客戶端並不須要作出修改,由於資源的 URI 和其餘信息都是動態發現的。

因此咱們能夠看到HATEOAS能夠下降客戶端和服務器之間的耦合。

咱們看看在Spring官網上的例子。

下面是一個類 Customer.

class Customer { String name; }

一個傳統的例子是:

{ 
    "name" : "Alice" }

若是變成HATEOAS風格的,能夠是下面這樣:

{
    "name": "Alice", "links": [ { "rel": "self", "href": "http://localhost:8080/customer/1" } ] }

咱們能夠看到,不只有了name,還多了一個links. links下的rel的值是self,意思就是說指向當前資源的連接。

關於ref的值,能夠參考下表:

rel 屬性值 描述
self 指向當前資源自己的連接的 rel 屬性。每一個資源的表達中都應該包含此關係的連接。
edit 指向一個能夠編輯當前資源的連接。
item 若是當前資源表示的是一個集合,則用來指向該集合中的單個資源。
collection 若是當前資源包含在某個集合中,則用來指向包含該資源的集合。
related 指向一個與當前資源相關的資源。
search 指向一個能夠搜索當前資源及其相關資源的連接。
first、last、previous、next 這幾個 rel 屬性值都有集合中的遍歷相關,分別用來指向集合中的第一個、最後一個、上一個和下一個資源。

 根據以上,咱們能夠清楚的看出根據rel不一樣的類型有不一樣的用處,這樣客戶端能夠智能的進行不一樣的操做,達到解耦的目的。

OpenAPI

其實RESTful API都是和OpenAPI相關的,爲何會把OpenAPI單獨拿出來講?原理很簡單,那是由於如今不少API的定義,包括一些大廠的,都作的不是很好。RESTful API設計的最佳實踐文檔就在這裏,可是大部分人仍是沒有去遵照。關於RESTful API文檔,建議去參考微軟的文章(  https://docs.microsoft.com/en-us/azure/architecture/best-practices/api-design)。那麼OpenAPI是幹什麼的?說白了就是爲了RESTful API,定義了一個標準,讓咱們和機器不用再去查看源代碼、文檔,甚至不用像我前面文件裏抓包那樣,去了解API的定義。 

最典型的例子仍是Swagger。Swagger的Editor等產品是支持OpenAPI的,總的來講,Open API的那些標準不是太難,由於現成的例子供參考。關鍵是若是利用這些將本身的產品變得更加標準,這是很重要的策略和思路。我原來在這個上面花了不少時間引入到項目裏,我以爲是值的,一個是讓產品規範了,有質的保證,二是讓本身和同事的思惟提升了

 

總的來講,這篇文章簡單介紹了5G和HTTP的關係,以及HTTP裏用到RESTful API,HTTP/2等技術,這和之前通訊領域是不同的。

參考文章:

相關文章
相關標籤/搜索