一篇文章讀懂 HTTP1.0 HTTP1.1 HTTP2.0 HTTPS

HTTP協(xié)議

超文本傳輸協(xié)議(HTTP,HyperText Transfer Protocol)是互聯(lián)網(wǎng)上應(yīng)用最為廣泛的一種網(wǎng)絡(luò)協(xié)議。所有的WWW文件都必須遵守這個標(biāo)準(zhǔn)。

設(shè)計HTTP最初的目的是為了將超文本標(biāo)記語言(HTML)文檔從Web服務(wù)器傳送到客戶端的瀏覽器。也是說對于前端來說,我們所寫的HTML頁面將要放在我們的 web 服務(wù)器上,用戶端通過瀏覽器訪問url地址來獲取網(wǎng)頁的顯示內(nèi)容;隨著web2.0的到來,我們的網(wǎng)站從單純的html網(wǎng)頁模式向內(nèi)容更豐富、更加注重交互并以用戶為中心的應(yīng)用創(chuàng)新,出現(xiàn)了如blog,sns等產(chǎn)品,同時我們的 HTML 頁面有了 CSS,Javascript,隨著Ajax的出現(xiàn)和大量使用,更是提升了我們對于網(wǎng)站交互的體驗,以上這些其實都是基于 HTTP 協(xié)議的;同樣到了移動互聯(lián)網(wǎng)時代,我們頁面可以跑在手機端瀏覽器里面,但是和 PC 相比,手機端的網(wǎng)絡(luò)情況更加復(fù)雜,這使得我們開始了不得不對 HTTP 進行深入理解并不斷優(yōu)化過程中。

超文本傳輸協(xié)議已經(jīng)演化出了很多版本,它們中的大部分都是向下兼容的。在RFC 2145中描述了HTTP版本號的用法??蛻舳嗽谡埱蟮拈_始告訴服務(wù)器它采用的協(xié)議版本號,而后者則在響應(yīng)中采用相同或者更早的協(xié)議版本。

HTTP 0.9

HTTP 是基于 TCP/IP 協(xié)議的應(yīng)用層協(xié)議,最早版本是1991年發(fā)布的0.9版。該版本極其簡單:

  • 只接受 GET 一種請求方法,且不支持請求頭。
  • 協(xié)議規(guī)定,服務(wù)器只能回應(yīng)HTML格式的字符串,不能回應(yīng)別的格式。
  • 由于該版本不支持 POST 方法,所以客戶端無法向服務(wù)器傳遞太多信息。
示例

客戶端請求格式
GET /index.html
服務(wù)器響應(yīng)格式

<html>
  <body>Hello World</body>
</html>

HTTP1.0

HTTP1.0最早在網(wǎng)頁中使用是在1996年,那個時候只是使用一些較為簡單的網(wǎng)頁上和網(wǎng)絡(luò)請求上。這是第一個在通訊中指定版本號的HTTP 協(xié)議版本,至今仍被廣泛采用,特別是在代理服務(wù)器中。

  • 首先,任何格式的內(nèi)容都可以發(fā)送。這使得互聯(lián)網(wǎng)不僅可以傳輸文字,還能傳輸圖像、視頻、二進制文件。這為互聯(lián)網(wǎng)的大發(fā)展奠定了基礎(chǔ)。
  • 其次,除了GET命令,還引入了POST命令和HEAD命令,豐富了瀏覽器與服務(wù)器的互動手段。
  • 再次,HTTP請求和回應(yīng)的格式也變了。除了數(shù)據(jù)部分,每次通信都必須包括頭信息(HTTP header),用來描述一些元數(shù)據(jù)。
  • 其他的新增功能還包括狀態(tài)碼(status code)、多字符集支持、多部分發(fā)送(multi-part type)、權(quán)限(authorization)、緩存(cache)、內(nèi)容編碼(content encoding)等。

客戶端請求格式

GET /index.html HTTP/1.0
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5)
Accept: */*

服務(wù)器響應(yīng)格式

HTTP/1.0 200 OK 
Content-Type: text/plain
Content-Length: 137582
Expires: Thu, 05 Dec 1997 16:00:00 GMT
Last-Modified: Wed, 5 August 1996 15:55:28 GMT
Server: Apache 0.84

<html>
  <body>Hello World</body>
</html>

回應(yīng)的格式是"頭信息 + 一個空行(\r\n) + 數(shù)據(jù)"。其中,第一行是"協(xié)議版本 + 狀態(tài)碼(status code) + 狀態(tài)描述"。

Content-Type 字段

關(guān)于字符的編碼,1.0版規(guī)定,頭信息必須是 ASCII 碼,后面的數(shù)據(jù)可以是任何格式。因此,服務(wù)器回應(yīng)的時候,必須告訴客戶端,數(shù)據(jù)是什么格式,這就是Content-Type字段的作用。

下面是一些常見的Content-Type字段的值:

text/plain
text/html
text/css
image/jpeg
image/png
image/svg+xml
audio/mp4
video/mp4
application/javascript
application/pdf
application/zip
application/atom+xml

這些數(shù)據(jù)類型總稱為MIME type,每個值包括一級類型和二級類型,之間用斜杠分隔。

除了預(yù)定義的類型,廠商也可以自定義類型。
application/vnd.debian.binary-package
上面的類型表明,發(fā)送的是Debian系統(tǒng)的二進制數(shù)據(jù)包。

MIME type還可以在尾部使用分號,添加參數(shù)。
Content-Type: text/html; charset=utf-8
上面的類型表明,發(fā)送的是網(wǎng)頁,而且編碼是UTF-8。

客戶端請求的時候,可以使用Accept字段聲明自己可以接受哪些數(shù)據(jù)格式。
Accept: */*
上面代碼中,客戶端聲明自己可以接受任何格式的數(shù)據(jù)。

MIME type不僅用在HTTP協(xié)議,還可以用在其他地方,比如HTML網(wǎng)頁。
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />等同于 <meta charset="utf-8" />

Content-Encoding 字段

由于發(fā)送的數(shù)據(jù)可以是任何格式,因此可以把數(shù)據(jù)壓縮后再發(fā)送。Content-Encoding字段說明數(shù)據(jù)的壓縮方法。

Content-Encoding: gzip
Content-Encoding: compress
Content-Encoding: deflate

客戶端在請求時,用Accept-Encoding字段說明自己可以接受哪些壓縮方法。
Accept-Encoding: gzip, deflate

缺點

HTTP/1.0 版的主要缺點是,每個TCP連接只能發(fā)送一個請求。發(fā)送數(shù)據(jù)完畢,連接就關(guān)閉,如果還要請求其他資源,就必須再新建一個連接。

TCP連接的新建成本很高,因為需要客戶端和服務(wù)器三次握手,并且開始時發(fā)送速率較慢(slow start)。所以,HTTP 1.0版本的性能比較差。隨著網(wǎng)頁加載的外部資源越來越多,這個問題就愈發(fā)突出了。

為了解決這個問題,有些瀏覽器在請求時,用了一個非標(biāo)準(zhǔn)的Connection字段。
Connection: keep-alive
這個字段要求服務(wù)器不要關(guān)閉TCP連接,以便其他請求復(fù)用。服務(wù)器同樣回應(yīng)這個字段。
Connection: keep-alive
一個可以復(fù)用的TCP連接就建立了,直到客戶端或服務(wù)器主動關(guān)閉連接。但是,這不是標(biāo)準(zhǔn)字段,不同實現(xiàn)的行為可能不一致,因此不是根本的解決辦法。

HTTP1.1

1997年1月,HTTP/1.1 版本發(fā)布,只比 1.0 版本晚了半年。它進一步完善了 HTTP 協(xié)議,一直用到了20年后的今天,直到現(xiàn)在還是最流行的版本。 持久連接被默認(rèn)采用,并能很好地配合代理服務(wù)器工作。還支持以管道方式同時發(fā)送多個請求,以便降低線路負(fù)載,提高傳輸速度。

持久連接

1.1 版的最大變化,就是引入了持久連接(persistent connection),即TCP連接默認(rèn)不關(guān)閉,可以被多個請求復(fù)用,不用聲明Connection: keep-alive

客戶端和服務(wù)器發(fā)現(xiàn)對方一段時間沒有活動,就可以主動關(guān)閉連接。不過,規(guī)范的做法是,客戶端在最后一個請求時,發(fā)送Connection: close,明確要求服務(wù)器關(guān)閉TCP連接。目前,對于同一個域名,大多數(shù)瀏覽器允許同時建立6個持久連接。

管道機制

1.1 版還引入了管道機制(pipelining),即在同一個TCP連接里面,客戶端可以同時發(fā)送多個請求。這樣就進一步改進了HTTP協(xié)議的效率。

舉例來說,客戶端需要請求兩個資源。以前的做法是,在同一個TCP連接里面,先發(fā)送A請求,然后等待服務(wù)器做出回應(yīng),收到后再發(fā)出B請求。管道機制則是允許瀏覽器同時發(fā)出A請求和B請求,但是服務(wù)器還是按照順序,先回應(yīng)A請求,完成后再回應(yīng)B請求。

Content-Length 字段

一個TCP連接現(xiàn)在可以傳送多個回應(yīng),勢必就要有一種機制,區(qū)分?jǐn)?shù)據(jù)包是屬于哪一個回應(yīng)的。這就是Content-length字段的作用,用于聲明本次回應(yīng)的數(shù)據(jù)長度。

Content-Length: 3495
上面代碼告訴瀏覽器,本次回應(yīng)的長度是3495個字節(jié),后面的字節(jié)就屬于下一個回應(yīng)了。

在1.0版中,Content-Length字段不是必需的,因為瀏覽器發(fā)現(xiàn)服務(wù)器關(guān)閉了TCP連接,就表明收到的數(shù)據(jù)包已經(jīng)全了。

分塊傳輸編碼

使用Content-Length字段的前提條件是,服務(wù)器發(fā)送回應(yīng)之前,必須知道回應(yīng)的數(shù)據(jù)長度。

對于一些很耗時的動態(tài)操作來說,這意味著,服務(wù)器要等到所有操作完成,才能發(fā)送數(shù)據(jù),顯然這樣的效率不高。更好的處理方法是,產(chǎn)生一塊數(shù)據(jù),就發(fā)送一塊,采用"流模式"(stream)取代"緩存模式"(buffer)。

因此,1.1版規(guī)定可以不使用Content-Length字段,而使用"分塊傳輸編碼"(chunked transfer encoding)。只要請求或回應(yīng)的頭信息有Transfer-Encoding字段,就表明回應(yīng)將由數(shù)量未定的數(shù)據(jù)塊組成。

Transfer-Encoding: chunked

每個非空的數(shù)據(jù)塊之前,會有一個16進制的數(shù)值,表示這個塊的長度。最后是一個大小為0的塊,就表示本次回應(yīng)的數(shù)據(jù)發(fā)送完了。下面是一個例子。

HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked

25
This is the data in the first chunk

1C
and this is the second one

3
con

8
sequence

0
緩存處理

在HTTP1.0中主要使用header里的If-Modified-Since,Expires來做為緩存判斷的標(biāo)準(zhǔn),HTTP1.1則引入了更多的緩存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供選擇的緩存頭來控制緩存策略。

Range 和 Content-Range 字段

HTTP1.1則在請求頭引入了RangeContent-Range 頭域,它允許只請求資源的某個部分,即返回碼是206(Partial Content),這樣就方便了開發(fā)者自由的選擇以便于充分利用帶寬和連接,把一個大的文件切割成小的文件塊傳輸,產(chǎn)生了我們所謂的斷點續(xù)傳功能;

Range用于請求頭中,指定第一個字節(jié)的位置和最后一個字節(jié)的位置,一般格式:
Range:(unit=first byte pos)-[last byte pos]

Content-Range用于響應(yīng)頭,指定整個實體中的一部分的插入位置,他也指示了整個實體的長度。在服務(wù)器向客戶返回一個部分響應(yīng),它必須描述響應(yīng)覆蓋的范圍和整個實體長度。一般格式:
Content-Range: bytes (unit first byte pos) - [last byte pos]/[entity legth]

錯誤通知的管理

在HTTP1.1中新增了24個錯誤狀態(tài)響應(yīng)碼,如409(Conflict)表示請求的資源與資源的當(dāng)前狀態(tài)發(fā)生沖突;410(Gone)表示服務(wù)器上的某個資源被永久性的刪除。

增加了多種請求方法

1.1版還新增了許多動詞方法:PUT、PATCHHEAD、 OPTIONSDELETE

http支持方法列表

Host頭處理

客戶端請求的頭信息新增了Host字段,用來指定服務(wù)器的域名。
Host: www.example.com

在HTTP1.0中認(rèn)為每臺服務(wù)器都綁定一個唯一的IP地址,因此,請求消息中的URL并沒有傳遞主機名(hostname)。但隨著虛擬主機技術(shù)的發(fā)展,在一臺物理服務(wù)器上可以存在多個虛擬主機(Multi-homed Web Servers),并且它們共享一個IP地址。HTTP1.1的請求消息和響應(yīng)消息都應(yīng)支持Host頭域,且請求消息中如果沒有Host頭域會報告一個錯誤(400 Bad Request)。

缺點

雖然1.1版允許復(fù)用TCP連接,但是同一個TCP連接里面,所有的數(shù)據(jù)通信是按次序進行的。服務(wù)器只有處理完一個回應(yīng),才會進行下一個回應(yīng)。要是前面的回應(yīng)特別慢,后面就會有許多請求排隊等著。這稱為"隊頭堵塞"(Head-of-line blocking)。

為了避免這個問題,只有兩種方法:一是減少請求數(shù),二是同時多開持久連接。這導(dǎo)致了很多的網(wǎng)頁優(yōu)化技巧,比如合并腳本和樣式表、將圖片嵌入CSS代碼、域名分片(domain sharding)等等。如果HTTP協(xié)議設(shè)計得更好一些,這些額外的工作是可以避免的。

SPDY 協(xié)議

2009年,谷歌公開了自行研發(fā)的 SPDY 協(xié)議,主要解決 HTTP/1.1 效率不高的問題。

SPDY(讀作“SPeeDY”)是Google開發(fā)的基于TCP的應(yīng)用層協(xié)議,用以最小化網(wǎng)絡(luò)延遲,提升網(wǎng)絡(luò)速度,優(yōu)化用戶的網(wǎng)絡(luò)使用體驗。SPDY并不是一種用于替代HTTP的協(xié)議,而是對HTTP協(xié)議的增強。新協(xié)議的功能包括數(shù)據(jù)流的多路復(fù)用、請求優(yōu)先級以及HTTP報頭壓縮。

互聯(lián)網(wǎng)工程任務(wù)組(IETF)對谷歌提出的SPDY協(xié)議進行了標(biāo)準(zhǔn)化,于2015年5推出了類似于SPDY協(xié)議的 HTTP 2.0 協(xié)議標(biāo)準(zhǔn)(簡稱HTTP/2)。谷歌因此宣布放棄對SPDY協(xié)議的支持,轉(zhuǎn)而支持HTTP/2。此外,著名的開源HTTP服務(wù)器軟件 Nginx 也于2015年9月移除了對SPDY的支持,轉(zhuǎn)而支持HTTP/2。因此,建議新的網(wǎng)站不要部署SPDY,轉(zhuǎn)為部署HTTP/2

所以,從歷史上來看,SPDY協(xié)議只是 HTTP/2 的基礎(chǔ),其主要特性都在 HTTP/2 之中得到繼承。鑒于此,我們不必要過多了解這個協(xié)議的具體內(nèi)容了。

HTTP/2

2015年,HTTP/2 發(fā)布。它不叫 HTTP/2.0,是因為標(biāo)準(zhǔn)委員會不打算再發(fā)布子版本了,下一個新版本將是 HTTP/3。

二進制協(xié)議

HTTP/1.1 版的頭信息肯定是文本(ASCII編碼),數(shù)據(jù)體可以是文本,也可以是二進制。HTTP/2 則是一個徹底的二進制協(xié)議,頭信息和數(shù)據(jù)體都是二進制,并且統(tǒng)稱為"幀"(frame):頭信息幀和數(shù)據(jù)幀。

二進制協(xié)議的一個好處是,可以定義額外的幀。HTTP/2 定義了近十種幀,為將來的高級應(yīng)用打好了基礎(chǔ)。如果使用文本實現(xiàn)這種功能,解析數(shù)據(jù)將會變得非常麻煩,二進制解析則方便得多。

既然又要保證HTTP的各種動詞,方法,首部都不受影響,那就需要在應(yīng)用層(HTTP2.0)和傳輸層(TCP or UDP)之間增加一個二進制分幀層。


二進制分幀層

在二進制分幀層上, HTTP/2 會將所有傳輸?shù)男畔⒎指顬楦〉南⒑蛶?并對它們采用二進制格式的編碼 ,其中HTTP1.x的首部信息會被封裝到Headers幀,而我們的request body則封裝到Data幀里面。

頭信息壓縮

HTTP 協(xié)議不帶有狀態(tài),每次請求都必須附上所有信息。所以,請求的很多字段都是重復(fù)的,比如Cookie和User Agent,一模一樣的內(nèi)容,每次請求都必須附帶,這會浪費很多帶寬,也影響速度。

HTTP/2 對這一點做了優(yōu)化,引入了頭信息壓縮機制(header compression)。一方面,頭信息使用gzip或compress壓縮后再發(fā)送;另一方面,客戶端和服務(wù)器同時維護一張“首部表”來跟蹤和存儲之前發(fā)送的鍵-值對,對于相同的數(shù)據(jù),不再通過每次請求和響應(yīng)發(fā)送;通信期間幾乎不會改變的通用鍵-值對(User Agent、Accept等等) 只需發(fā)送一次。

事實上,如果請求中不包含首部(例如對同一資源的輪詢請求),那么 首部開銷就是零字節(jié)。此時所有首部都自動使用之前請求發(fā)送的首部。

如果首部發(fā)生變化了,那么只需要發(fā)送變化了數(shù)據(jù)在Headers幀里面,新增或修改的首部幀會被追加到“首部表”。首部表在 HTTP 2.0 的連接存續(xù)期內(nèi)始終存在,由客戶端和服務(wù)器共同漸進地更新 。

多路復(fù)用

上面我們說過了HTTP1.1協(xié)議的"隊頭堵塞"問題,在HTTP1.1的協(xié)議中,我們傳輸?shù)膔equest和response都是基本于文本的,這樣就會引發(fā)一個問題:所有的數(shù)據(jù)必須按順序傳輸,比如需要傳輸:hello world,只能從hd一個一個的傳輸,不能并行傳輸,因為接收端并不知道這些字符的順序,所以并行傳輸在HTTP1.1是不能實現(xiàn)的。

http1.1順序傳輸

然而HTTP/2協(xié)議中,我們可以復(fù)用TCP連接,在一個連接里,客戶端和瀏覽器都可以同時發(fā)送多個請求或回應(yīng),而且不用按照順序一一對應(yīng),這樣就避免了"隊頭堵塞"。

HTTP/2 復(fù)用TCP連接 并行傳輸

舉例來說,在一個TCP連接里面,服務(wù)器同時收到了A請求和B請求,于是先回應(yīng)A請求,結(jié)果發(fā)現(xiàn)處理過程非常耗時,于是就發(fā)送A請求已經(jīng)處理好的部分, 接著回應(yīng)B請求,完成后,再發(fā)送A請求剩下的部分。

我們來看一個HTTP/2 的網(wǎng)站:

屏幕快照 2018-05-25 上午10.14.36.png

Protocol為h2的就是HTTP/2協(xié)議的請求,我們從上圖中可以看出,所有該協(xié)議的請求都使用的同一個ConnectionID。我們再從Timing來看下兩種協(xié)議的對比

HTTP1.1協(xié)議請求
HTTP/2 協(xié)議請求

由于多路復(fù)用,HTTP/2 協(xié)議比HTTP1.1協(xié)議省去了DNS Lookup,Initial connection,SSL這些建立連接的步驟,大大提升了網(wǎng)站響應(yīng)時間。

數(shù)據(jù)流 Stream

因為 HTTP/2 的數(shù)據(jù)包是不按順序發(fā)送的,同一個連接里面連續(xù)的數(shù)據(jù)包,可能屬于不同的回應(yīng)。因此,必須要對數(shù)據(jù)包做標(biāo)記,指出它屬于哪個回應(yīng)。

HTTP/2 將每個請求或回應(yīng)的所有數(shù)據(jù)包,稱為一個數(shù)據(jù)流(stream)。每個數(shù)據(jù)流都有一個獨一無二的編號。數(shù)據(jù)包發(fā)送的時候,都必須標(biāo)記數(shù)據(jù)流ID,用來區(qū)分它屬于哪個數(shù)據(jù)流。另外還規(guī)定,客戶端發(fā)出的數(shù)據(jù)流,ID一律為奇數(shù),服務(wù)器發(fā)出的,ID為偶數(shù)。

stream.jpg

數(shù)據(jù)流發(fā)送到一半的時候,客戶端和服務(wù)器都可以發(fā)送信號(RST_STREAM幀),取消這個數(shù)據(jù)流。1.1版取消數(shù)據(jù)流的唯一方法,就是關(guān)閉TCP連接。這就是說,HTTP/2 可以取消某一次請求,同時保證TCP連接還打開著,可以被其他請求使用。

客戶端還可以指定數(shù)據(jù)流的優(yōu)先級。優(yōu)先級越高,服務(wù)器就會越早回應(yīng)。

服務(wù)器推送

HTTP/2 允許服務(wù)器未經(jīng)請求,主動向客戶端發(fā)送資源,這叫做服務(wù)器推送(server push)。

常見場景是客戶端請求一個網(wǎng)頁,這個網(wǎng)頁里面包含很多靜態(tài)資源。正常情況下,客戶端必須收到網(wǎng)頁后,解析HTML源碼,發(fā)現(xiàn)有靜態(tài)資源,再發(fā)出靜態(tài)資源請求。其實,服務(wù)器可以預(yù)期到客戶端請求網(wǎng)頁后,很可能會再請求靜態(tài)資源,所以就主動把這些靜態(tài)資源隨著網(wǎng)頁一起發(fā)給客戶端了。

HTTPS

HTTPS(全稱:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全為目標(biāo)的HTTP通道,簡單講是HTTP的安全版。即HTTP下加入SSL層,HTTPS的安全基礎(chǔ)是SSL,用于安全的HTTP數(shù)據(jù)傳輸。

https的安全傳輸

超文本傳輸協(xié)議HTTP協(xié)議被用于在Web瀏覽器和網(wǎng)站服務(wù)器之間傳遞信息。HTTP協(xié)議以明文方式發(fā)送內(nèi)容,不提供任何方式的數(shù)據(jù)加密,如果攻擊者截取了Web瀏覽器和網(wǎng)站服務(wù)器之間的傳輸報文,就可以直接讀懂其中的信息,因此HTTP協(xié)議不適合傳輸一些敏感信息,比如信用卡號、密碼等。

SSL(Secure Sockets Layer 安全套接層),及其繼任者 TLS(Transport Layer Security 傳輸層安全)是為網(wǎng)絡(luò)通信提供安全及數(shù)據(jù)完整性的一種安全協(xié)議。TLS與SSL在傳輸層對網(wǎng)絡(luò)連接進行加密。HTTPS就是在HTTP的基礎(chǔ)上加入了SSL協(xié)議,SSL依靠證書來驗證服務(wù)器的身份,并為瀏覽器和服務(wù)器之間的通信加密。

HTTPS和HTTP的區(qū)別
  1. https協(xié)議需要到ca申請證書,一般免費證書很少,需要交費。
  2. http是超文本傳輸協(xié)議,信息是明文傳輸,https 則是具有安全性的ssl加密傳輸協(xié)議。
  3. http和https使用的是完全不同的連接方式,用的端口也不一樣,前者是80,后者是443。
  4. http的連接很簡單,是無狀態(tài)的;HTTPS協(xié)議是由SSL+HTTP協(xié)議構(gòu)建的可進行加密傳輸、身份認(rèn)證的網(wǎng)絡(luò)協(xié)議,比http協(xié)議安全。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容