4.2 服務(wù)器的相關(guān)知識(shí)
因?yàn)檎嬲暮笈_(tái)應(yīng)用是需要在服務(wù)器上面運(yùn)行的,因此有必要在這里補(bǔ)充一下關(guān)于服務(wù)器的知識(shí)。
我們用到的大部分網(wǎng)絡(luò)應(yīng)用各拷,如APP、Web網(wǎng)站闷营、PC客戶(hù)端甚至銀行取款機(jī)的背后都提供了一個(gè)強(qiáng)大的后臺(tái)服務(wù)烤黍,無(wú)論是電商、銀行抑或游戲服務(wù)粮坞,對(duì)于一個(gè)用戶(hù)來(lái)講蚊荣,我們感受到的僅僅是數(shù)據(jù)的傳遞和渲染,但是這些數(shù)據(jù)是怎么被匯總莫杈、計(jì)算或者存儲(chǔ)的互例,大部分人無(wú)從得知,甚至感覺(jué)這一切是非常自然的事情筝闹。然則媳叨,事實(shí)并非如此。
目前关顷,大部分網(wǎng)絡(luò)應(yīng)用都是搭建在分布式集群網(wǎng)絡(luò)服務(wù)器上的糊秆,成千上萬(wàn)的服務(wù)器相互之間協(xié)調(diào),聯(lián)系议双,共享數(shù)據(jù)痘番,構(gòu)成了一個(gè)覆蓋每一個(gè)用戶(hù)的服務(wù)網(wǎng)絡(luò)。
4.2.1 服務(wù)器概念
服務(wù)器就是一臺(tái)高性能的計(jì)算機(jī)平痰,它的高性能主要體現(xiàn)在高速度的運(yùn)算能力汞舱、長(zhǎng)時(shí)間的可靠運(yùn)行、強(qiáng)大的外部數(shù)據(jù)吞吐能力等方面宗雇。服務(wù)器的構(gòu)成與家用電腦基本相似昂芜,包括處理器、硬盤(pán)赔蒲、內(nèi)存泌神、系統(tǒng)總線等,但它們是針對(duì)具體的網(wǎng)絡(luò)應(yīng)用特別制定的舞虱,因而服務(wù)器與微機(jī)在處理能力欢际、穩(wěn)定性、可靠性矾兜、安全性幼苛、可擴(kuò)展性、可管理性等方面差異很大焕刮。
我們搭建的后臺(tái)應(yīng)用在生產(chǎn)環(huán)境下都是搭建在服務(wù)器上面的舶沿,因?yàn)榉?wù)器可以保證24小時(shí)不間斷工作墙杯,而且能夠保證很好地網(wǎng)絡(luò)吞吐能力。而對(duì)于每一個(gè)用戶(hù)來(lái)講括荡,在資源有限的情況的下高镐,一個(gè)服務(wù)器的資源是被多個(gè)用戶(hù)共享的,因此在硬件限制的情況下畸冲,就需要考慮軟件的編寫(xiě)來(lái)優(yōu)化用戶(hù)的請(qǐng)求和處理嫉髓,保證每個(gè)用戶(hù)能夠公平流暢的享受服務(wù)。
服務(wù)器長(zhǎng)這個(gè)樣子邑闲,里面安裝的是Linux或WindowsServer系統(tǒng)哦
4.2.2 TCP/IP和HTTP協(xié)議
一個(gè)沒(méi)有聯(lián)網(wǎng)的單個(gè)服務(wù)器算行,除了能夠當(dāng)做一個(gè)大型的計(jì)算機(jī)之外,沒(méi)有任何用途苫耸。只有把服務(wù)器之間聯(lián)網(wǎng)州邢,服務(wù)器和用戶(hù)的電腦之間聯(lián)網(wǎng)才能讓用戶(hù)和網(wǎng)絡(luò)服務(wù)器提供商真正的建立聯(lián)系。那么用戶(hù)的瀏覽器和提供商的服務(wù)器的Web應(yīng)用是怎么通過(guò)網(wǎng)絡(luò)取得聯(lián)系的呢褪子?
為了解決這個(gè)問(wèn)題量淌,計(jì)算機(jī)網(wǎng)絡(luò)分層體系和網(wǎng)絡(luò)協(xié)議應(yīng)運(yùn)而生:
互聯(lián)網(wǎng)協(xié)議按照功能不同分為OSI七層或TCP/IP五層或TCP/IP四層,搞清楚了每層的主要協(xié)議
就理解了整個(gè)互聯(lián)網(wǎng)通信的原理嫌褪。每層都運(yùn)行特定的協(xié)議呀枢,越往上越靠近用戶(hù),越往下越靠近硬件笼痛。
什么是協(xié)議裙秋?
所謂協(xié)議就是互聯(lián)網(wǎng)設(shè)備之間通信需要遵循的一套規(guī)則或者標(biāo)準(zhǔn),消息的發(fā)送者和接收者都需要遵循這個(gè)標(biāo)準(zhǔn)才能理解對(duì)方表達(dá)的意思缨伊。
數(shù)據(jù)鏈路層:以太網(wǎng)協(xié)議屬于數(shù)據(jù)鏈路層協(xié)議残吩。
?以太網(wǎng)協(xié)議規(guī)定:
一組信號(hào)構(gòu)成一個(gè)數(shù)據(jù)包,叫做‘幀’
每一數(shù)據(jù)幀分成:報(bào)頭head和數(shù)據(jù)data兩部分
?
headdata
?
head包含:(固定18個(gè)字節(jié))
發(fā)送者/源地址倘核,6個(gè)字節(jié)
接收者/目標(biāo)地址,6個(gè)字節(jié)
數(shù)據(jù)類(lèi)型即彪,6個(gè)字節(jié)
data包含:(最短46字節(jié)紧唱,最長(zhǎng)1500字節(jié))
數(shù)據(jù)包的具體內(nèi)容
目標(biāo)地址/源地址指代的就是mac地址,也就是我們電腦或通信設(shè)備的網(wǎng)卡地址隶校,mac地址在全世界都是唯一的漏益。
有了mac地址,同一網(wǎng)絡(luò)內(nèi)的兩臺(tái)主機(jī)就可以通信了深胳,但以太網(wǎng)協(xié)議采用最原始的方式——廣播的方式進(jìn)行通信绰疤,即計(jì)算機(jī)通信基本靠吼。
網(wǎng)絡(luò)層:IP協(xié)議屬于網(wǎng)絡(luò)層的協(xié)議舞终。
如果所有的通信都采用以太網(wǎng)的廣播方式轻庆,那么一臺(tái)機(jī)器發(fā)送的包全世界都會(huì)收到癣猾,這簡(jiǎn)直難以想象。因此網(wǎng)絡(luò)層就出現(xiàn)了余爆。
世界上的大的網(wǎng)絡(luò)由一個(gè)個(gè)小型的局域網(wǎng)組成纷宇,這樣讓以太網(wǎng)的包只能在局域網(wǎng)中傳播可以避免隨意亂吼,但是還必須保證某個(gè)以太網(wǎng)設(shè)備可以連接另外一個(gè)局域網(wǎng)的設(shè)備蛾方。因此像捶,必須找出一種方法來(lái)區(qū)分哪些計(jì)算機(jī)屬于同一廣播域师脂,哪些不是巷送,如果是就采用廣播的方式發(fā)送祭衩,如果不是稽亏,就采用路由的方式(向不同廣播域/子網(wǎng)分發(fā)數(shù)據(jù)包)墩崩。
網(wǎng)絡(luò)層功能:引入一套新的地址用來(lái)區(qū)分不同的廣播域/子網(wǎng)亮曹,這套地址即網(wǎng)絡(luò)地址缀棍。
IP協(xié)議:
規(guī)定網(wǎng)絡(luò)地址的協(xié)議叫IP協(xié)議彪见,它定義的地址稱(chēng)之為IP地址枢步,廣泛采用的v4版本即IPv4沉删,它規(guī)定網(wǎng)絡(luò)地址由32位2進(jìn)制表示(現(xiàn)在IPv4早已經(jīng)不夠用啦,IPv6已經(jīng)出來(lái)了)醉途。
范圍0.0.0.0-255.255.255.255
一個(gè)IP地址通常寫(xiě)成四段十進(jìn)制數(shù)矾瑰,例:172.16.10.1
ip地址分成兩部分
網(wǎng)絡(luò)部分:標(biāo)識(shí)子網(wǎng)
主機(jī)部分:標(biāo)識(shí)主機(jī)
但是注意:?jiǎn)渭兊腎P地址段只是標(biāo)識(shí)了IP地址的種類(lèi),從網(wǎng)絡(luò)部分或主機(jī)部分都無(wú)法辨識(shí)一個(gè)IP所處的子網(wǎng)隘擎,但是可以利用子網(wǎng)掩碼來(lái)解決這個(gè)問(wèn)題殴穴。
例:172.16.10.1與172.16.10.2并不能確定二者處于同一子網(wǎng)
所謂”子網(wǎng)掩碼”,就是表示子網(wǎng)絡(luò)特征的一個(gè)參數(shù)货葬。它在形式上等同于IP地址采幌,也是一個(gè)32位二進(jìn)制數(shù)字,它的網(wǎng)絡(luò)部分全部為1震桶,主機(jī)部分全部為0休傍。比如,IP地址172.16.10.1蹲姐,如果已知網(wǎng)絡(luò)部分是前24位磨取,主機(jī)部分是后8位,那么子網(wǎng)絡(luò)掩碼就是11111111.11111111.11111111.00000000柴墩,寫(xiě)成十進(jìn)制就是255.255.255.0忙厌。
知道”子網(wǎng)掩碼”,我們就能判斷江咳,任意兩個(gè)IP地址是否處在同一個(gè)子網(wǎng)絡(luò)逢净。方法是將兩個(gè)IP地址與子網(wǎng)掩碼分別進(jìn)行AND運(yùn)算(兩個(gè)數(shù)位都為1,運(yùn)算結(jié)果為1,否則為0)爹土,然后比較結(jié)果是否相同甥雕,如果是的話,就表明它們?cè)谕粋€(gè)子網(wǎng)絡(luò)中着饥,否則就不是犀农。
子網(wǎng)掩碼的知識(shí)不需要深入了解,我們只需要知道:
IP協(xié)議的作用主要有兩個(gè)宰掉,一個(gè)是為每一臺(tái)計(jì)算機(jī)分配IP地址呵哨,另一個(gè)是確定哪些地址在同一個(gè)子網(wǎng)絡(luò)。
IP數(shù)據(jù)包也分為head和data部分轨奄,無(wú)須為IP包定義單獨(dú)的欄位孟害,直接放入以太網(wǎng)包的data部分。
?
以太網(wǎng) headIP headIP data
?
傳輸層:TCP協(xié)議屬于傳輸層的協(xié)議挪拟。
以太網(wǎng)層的mac幫我們找到主機(jī)挨务,網(wǎng)絡(luò)層的IP幫我們區(qū)分子網(wǎng),這樣基本就能定位到是網(wǎng)絡(luò)上的哪個(gè)設(shè)備了玉组。但是大家在一個(gè)設(shè)備上使用了很多的應(yīng)用程序谎柄,你的電腦上可能同時(shí)開(kāi)啟qq,chrome惯雳,穿越火線等多個(gè)應(yīng)用程序朝巫,如何讓通信直接聯(lián)絡(luò)到某個(gè)應(yīng)用程序呢?答案就是端口石景,端口即應(yīng)用程序與網(wǎng)卡關(guān)聯(lián)的編號(hào)劈猿。
傳輸層功能:建立端口到端口的通信。端口范圍0-65535潮孽,但0-1023為系統(tǒng)占用端口揪荣,不能給普通應(yīng)用程序使用。
TCP協(xié)議:
TCP協(xié)議是可靠的傳輸往史,TCP數(shù)據(jù)包的長(zhǎng)度一般不會(huì)超過(guò)IP數(shù)據(jù)包的長(zhǎng)度仗颈,以確保單個(gè)TCP數(shù)據(jù)包不必再分割。
?
以太網(wǎng) headIP headTCP headTCP data
?
UDP協(xié)議:
UDP協(xié)議是不可靠傳輸椎例,”報(bào)頭”部分一共只有8個(gè)字節(jié)挨决,總長(zhǎng)度不超過(guò)65,535字節(jié),正好放進(jìn)一個(gè)IP數(shù)據(jù)包粟矿。
?
以太網(wǎng) headIP headUDP head(8Bytes)UDP data
?
TCP和UDP協(xié)議到底有何優(yōu)劣
UDP提供簡(jiǎn)單的通信機(jī)制,傳輸過(guò)程中丟包或者包內(nèi)容順序錯(cuò)亂也無(wú)法檢測(cè)重發(fā)损拢。但是UDP協(xié)議的頭部信息更少陌粹,可以承載更多的數(shù)據(jù)。同時(shí)能夠避免TCP的三次握手福压,達(dá)到更高的傳輸效率掏秩,適用于DNS通信解析和音視頻流媒體傳輸或舞。
TCP相比UDP可以保證可靠的傳輸,能夠檢測(cè)包的完整性蒙幻,同時(shí)它是有連接的協(xié)議(需要確保對(duì)方可以通信時(shí)才發(fā)送數(shù)據(jù))映凳。
TCP通過(guò)三次握手來(lái)建立連接(重點(diǎn))
所謂TCP三次握手是指建立一個(gè) TCP 連接時(shí)需要客戶(hù)端和服務(wù)器端總共發(fā)送三個(gè)包以確認(rèn)連接的建立。在socket編程中邮破,這一過(guò)程由客戶(hù)端執(zhí)行connect來(lái)觸發(fā)诈豌。
第一次握手:客戶(hù)端將標(biāo)志位SYN置為1,隨機(jī)產(chǎn)生一個(gè)值seq=J抒和,并將該數(shù)據(jù)包發(fā)送給服務(wù)器端矫渔,客戶(hù)端進(jìn)入SYN_SENT狀態(tài),等待服務(wù)器端確認(rèn)摧莽。
第二次握手:服務(wù)器端收到數(shù)據(jù)包后由標(biāo)志位SYN=1知道客戶(hù)端請(qǐng)求建立連接庙洼,服務(wù)器端將標(biāo)志位SYN和ACK都置為1,ack=J+1镊辕,隨機(jī)產(chǎn)生一個(gè)值seq=K油够,并將該數(shù)據(jù)包發(fā)送給客戶(hù)端以確認(rèn)連接請(qǐng)求,服務(wù)器端進(jìn)入SYN_RCVD狀態(tài)征懈。
第三次握手:客戶(hù)端收到確認(rèn)后石咬,檢查ack是否為J+1,ACK是否為1受裹,如果正確則將標(biāo)志位ACK置為1碌补,ack=K+1,并將該數(shù)據(jù)包發(fā)送給服務(wù)器端棉饶,服務(wù)器端檢查ack是否為K+1厦章,ACK是否為1,如果正確則連接建立成功照藻,客戶(hù)端和服務(wù)器端進(jìn)入ESTABLISHED狀態(tài)袜啃,完成三次握手,隨后客戶(hù)端與服務(wù)器端之間可以開(kāi)始傳輸數(shù)據(jù)了幸缕。
TCP通過(guò)四次握手來(lái)終止連接(重點(diǎn))
斷開(kāi)一個(gè)TCP連接時(shí)群发,需要客戶(hù)端和服務(wù)端總共發(fā)送4個(gè)包以確認(rèn)連接的斷開(kāi)。在socket編程中发乔,這一過(guò)程由客戶(hù)端或服務(wù)端任一方執(zhí)行close來(lái)觸發(fā)熟妓。
由于TCP連接是全雙工的,因此栏尚,每個(gè)方向都必須要單獨(dú)進(jìn)行關(guān)閉起愈,這一原則是當(dāng)一方完成數(shù)據(jù)發(fā)送任務(wù)后,發(fā)送一個(gè)FIN來(lái)終止這一方向的連接,收到一個(gè)FIN只是意味著這一方向上沒(méi)有數(shù)據(jù)流動(dòng)了抬虽,即不會(huì)再收到數(shù)據(jù)了官觅,但是在這個(gè)TCP連接上仍然能夠發(fā)送數(shù)據(jù),直到這一方向也發(fā)送了FIN阐污。首先進(jìn)行關(guān)閉的一方將執(zhí)行主動(dòng)關(guān)閉休涤,而另一方則執(zhí)行被動(dòng)關(guān)閉。
? ? ? 中斷連接端可以是客戶(hù)端笛辟,也可以是服務(wù)器端功氨。
第一次揮手:客戶(hù)端發(fā)送一個(gè)FIN=M,用來(lái)關(guān)閉客戶(hù)端到服務(wù)器端的數(shù)據(jù)傳送隘膘,客戶(hù)端進(jìn)入FIN_WAIT_1狀態(tài)疑故。意思是說(shuō)"我客戶(hù)端沒(méi)有數(shù)據(jù)要發(fā)給你了",但是如果你服務(wù)器端還有數(shù)據(jù)沒(méi)有發(fā)送完成弯菊,則不必急著關(guān)閉連接纵势,可以繼續(xù)發(fā)送數(shù)據(jù)。
第二次揮手:服務(wù)器端收到FIN后管钳,先發(fā)送ack=M+1钦铁,告訴客戶(hù)端,你的請(qǐng)求我收到了才漆,但是我還沒(méi)準(zhǔn)備好牛曹,請(qǐng)繼續(xù)你等我的消息。這個(gè)時(shí)候客戶(hù)端就進(jìn)入FIN_WAIT_2 狀態(tài)醇滥,繼續(xù)等待服務(wù)器端的FIN報(bào)文黎比。
第三次揮手:當(dāng)服務(wù)器端確定數(shù)據(jù)已發(fā)送完成,則向客戶(hù)端發(fā)送FIN=N報(bào)文鸳玩,告訴客戶(hù)端阅虫,好了,我這邊數(shù)據(jù)發(fā)完了不跟,準(zhǔn)備好關(guān)閉連接了颓帝。服務(wù)器端進(jìn)入LAST_ACK狀態(tài)。
第四次揮手:客戶(hù)端收到FIN=N報(bào)文后窝革,就知道可以關(guān)閉連接了购城,但是他還是不相信網(wǎng)絡(luò),怕服務(wù)器端不知道要關(guān)閉虐译,所以發(fā)送ack=N+1后進(jìn)入TIME_WAIT狀態(tài)瘪板,如果Server端沒(méi)有收到ACK則可以重傳。服務(wù)器端收到ACK后漆诽,就知道可以斷開(kāi)連接了侮攀∈仿拢客戶(hù)端等待了2MSL后依然沒(méi)有收到回復(fù),則證明服務(wù)器端已正常關(guān)閉魏身,那好,我客戶(hù)端也可以關(guān)閉連接了蚪腐。最終完成了四次握手箭昵。
應(yīng)用層協(xié)議:HTTP、HTTPS協(xié)議是應(yīng)用層協(xié)議回季。
用戶(hù)使用的應(yīng)用程序均工作于應(yīng)用層家制,但大家都可以開(kāi)發(fā)自己的應(yīng)用程序,而且數(shù)據(jù)多種多樣泡一,必須規(guī)定好數(shù)據(jù)的組織形式才能保證可以解析數(shù)據(jù)颤殴。
應(yīng)用層功能:規(guī)定應(yīng)用程序的數(shù)據(jù)格式。
HTTP協(xié)議也叫超文本傳輸協(xié)議鼻忠,是一個(gè)基于請(qǐng)求與響應(yīng)模式的涵但、無(wú)狀態(tài)的、應(yīng)用層的協(xié)議帖蔓。瀏覽器地址欄輸入的URL矮瘟,大部分都是基于HTTP或HTTPS協(xié)議的網(wǎng)址。
HTTP協(xié)議的組成
HTTP協(xié)議分請(qǐng)求和響應(yīng)兩部分規(guī)范:
請(qǐng)求:請(qǐng)求行(請(qǐng)求方法+URI+客戶(hù)端協(xié)議版本)+消息報(bào)頭+請(qǐng)求數(shù)據(jù)塑娇。
響應(yīng):狀態(tài)行(服務(wù)器協(xié)議版本+狀態(tài)碼+狀態(tài)碼文本描述)+消息報(bào)頭+響應(yīng)數(shù)據(jù)澈侠。
HTTP是一個(gè)無(wú)狀態(tài)的協(xié)議,無(wú)狀態(tài)是指協(xié)議對(duì)于事務(wù)處理沒(méi)有記憶能力埋酬,服務(wù)器不知道客戶(hù)端是什么狀態(tài)哨啃。即我們給服務(wù)器發(fā)送 HTTP 請(qǐng)求之后,服務(wù)器根據(jù)請(qǐng)求写妥,會(huì)給我們發(fā)送數(shù)據(jù)過(guò)來(lái)拳球,但是,發(fā)送完耳标,不會(huì)記錄任何信息醇坝。這意味著每個(gè)請(qǐng)求都是獨(dú)立的,后續(xù)請(qǐng)求無(wú)法依賴(lài)上一次請(qǐng)求來(lái)判斷身份次坡,后續(xù)我們會(huì)學(xué)到如何解決HTTP無(wú)狀態(tài)的問(wèn)題呼猪。
1.0協(xié)議:
服務(wù)器需要處理同時(shí)面向全世界數(shù)十萬(wàn)、上百萬(wàn)客戶(hù)端的網(wǎng)頁(yè)訪問(wèn)砸琅,但每個(gè)客戶(hù)端與服務(wù)器之間交換數(shù)據(jù)的間歇性較大(即傳輸具有突發(fā)性宋距、瞬時(shí)性),并且網(wǎng)頁(yè)瀏覽的聯(lián)想性症脂、發(fā)散性導(dǎo)致兩次傳送的數(shù)據(jù)關(guān)聯(lián)性很低谚赎,大部分通道實(shí)際上會(huì)很空閑淫僻、無(wú)端占用資源。因此 HTTP 的設(shè)計(jì)者有意利用這種特點(diǎn)將協(xié)議設(shè)計(jì)為請(qǐng)求時(shí)建連接壶唤、請(qǐng)求完釋放連接雳灵,以盡快將資源釋放出來(lái)服務(wù)其他客戶(hù)端。
2.0協(xié)議:
隨著時(shí)間的推移闸盔,網(wǎng)頁(yè)變得越來(lái)越復(fù)雜悯辙,里面可能嵌入了很多圖片,這時(shí)候每次訪問(wèn)圖片都需要建立一次 TCP 連接就顯得很低效迎吵。后來(lái)躲撰,Keep-Alive 被提出用來(lái)解決這效率低的問(wèn)題。
Keep-Alive 功能使客戶(hù)端到服務(wù)器端的連接持續(xù)有效击费,當(dāng)出現(xiàn)對(duì)服務(wù)器的后繼請(qǐng)求時(shí)拢蛋,Keep-Alive 功能避免了建立或者重新建立連接。
HTTPS協(xié)議
HTTPS協(xié)議是在HTTPS協(xié)議的基礎(chǔ)上對(duì)報(bào)文進(jìn)行加密的協(xié)議蔫巩,因此HTTPS協(xié)議更安全谆棱。
HTTPS協(xié)議需要到CA申請(qǐng)證書(shū)。CA(數(shù)字證書(shū)認(rèn)證圆仔,Certificate Authority)機(jī)構(gòu)础锐,是承擔(dān)公鑰合法性檢驗(yàn)的第三方權(quán)威機(jī)構(gòu),負(fù)責(zé)指定政策荧缘、步驟來(lái)驗(yàn)證用戶(hù)的身份皆警,并對(duì)SSL證書(shū)進(jìn)行簽名,確保證書(shū)持有者的身份和公鑰的所有權(quán)截粗。
SSL證書(shū)可加密敏感信息使其不被泄露信姓,還可以提供身份驗(yàn)證,防止釣魚(yú)網(wǎng)站绸罗,SSL證書(shū)是由受信任的CA機(jī)構(gòu)頒發(fā)的意推,申請(qǐng)證書(shū)時(shí)會(huì)嚴(yán)格的驗(yàn)證企業(yè)/組織的信息,可以消除瀏覽器“不安全”提示珊蟀。最后SSL證書(shū)還可以提高SEO關(guān)鍵詞排名菊值,谷歌、百度等瀏覽器育灸,明確表示對(duì)安裝SSL證書(shū)的網(wǎng)站進(jìn)行優(yōu)先暫時(shí)排名的權(quán)利腻窒。
SSL證書(shū)的頒發(fā)和HTTPS訪問(wèn)流程:
用戶(hù)產(chǎn)生自己的密鑰對(duì),把公鑰和身份信息發(fā)送給CA認(rèn)證中心磅崭。
CA核實(shí)之后把數(shù)字證書(shū)發(fā)送給用戶(hù)儿子,該證書(shū)包含用戶(hù)的個(gè)人信息和公鑰,附帶認(rèn)證中心的私鑰簽名砸喻。
用戶(hù)把認(rèn)證證書(shū)放在網(wǎng)站下柔逼,通過(guò)HTTPS提供服務(wù)蒋譬。
瀏覽器內(nèi)置了各大權(quán)威CA機(jī)構(gòu)根證書(shū),也就包含了CA的公鑰愉适,和用戶(hù)網(wǎng)站進(jìn)行公鑰私鑰比對(duì)就能建立HTTPS/SSL連接犯助。
4.2.3 瀏覽器請(qǐng)求接收流程
打開(kāi)Chrome瀏覽器,地址欄輸入了網(wǎng)址:https://www.google.com的執(zhí)行流程:
通過(guò)DNS進(jìn)行域名解析维咸,我們?cè)L問(wèn)的是一個(gè)域名https://www.google.com也切,但是網(wǎng)絡(luò)設(shè)備只能通過(guò)ip地址才能找到對(duì)方的主機(jī)。因此首先需要域名解析:
Chrome先從自身DNS緩存中找腰湾,但瀏覽器只能緩存1000條。
如果瀏覽器找不到疆股,會(huì)查看操作系統(tǒng)的DNS緩存费坊。
如果操作系統(tǒng)也沒(méi)有找到,則會(huì)根據(jù)本機(jī)配置的首選DNS服務(wù)器發(fā)起域名解析請(qǐng)求(UDP協(xié)議的DNS 53端口)旬痹。
DNS運(yùn)營(yíng)商首先從自身查找解析附井,找不到就迭代的去世界根DNS服務(wù)器查找(世界有13臺(tái)根DNS服務(wù)器)。
最后找到了域名對(duì)應(yīng)的IP地址两残,則開(kāi)始下一步動(dòng)作永毅。
瀏覽器根據(jù)IP,遵循網(wǎng)絡(luò)協(xié)議找到對(duì)方主機(jī)人弓,開(kāi)始建立TCP的3次握手沼死。
瀏覽器會(huì)以隨機(jī)端口向服務(wù)器發(fā)送TCP請(qǐng)求,這中間要經(jīng)過(guò)各種網(wǎng)絡(luò)設(shè)備崔赌,甚至還要經(jīng)過(guò)層層防火墻意蛀。
建立TCP連接后開(kāi)始發(fā)送HTTP請(qǐng)求,服務(wù)器響應(yīng)HTTP請(qǐng)求健芭,生成HTML頁(yè)面代碼作為響應(yīng)體數(shù)據(jù)發(fā)送給瀏覽器县钥。
Chrome瀏覽器利用Webkit內(nèi)核解析HTML和CSS ,利用V8內(nèi)核解析JavaScript慈迈,請(qǐng)附帶請(qǐng)求其他資源若贮。
瀏覽器解析的結(jié)果會(huì)生成一個(gè)DOM樹(shù)和CSS規(guī)則樹(shù),組合構(gòu)造成一個(gè)渲染樹(shù)痒留。
渲染樹(shù)并不等同于 DOM 樹(shù)谴麦,渲染樹(shù)只會(huì)包括需要顯示的節(jié)點(diǎn)和這些節(jié)點(diǎn)的樣式信息。
CSS 規(guī)則樹(shù) 主要是為了完成匹配并把 CSS規(guī)則 附加到渲染樹(shù)上的每個(gè) 元素上面伸头。
當(dāng)瀏覽器生成渲染樹(shù)以后细移,就會(huì)根據(jù)渲染樹(shù)來(lái)進(jìn)行布局(也可以叫做回流)。這一階段瀏覽器要做的事情是要弄清楚各個(gè)節(jié)點(diǎn)在頁(yè)面中的確切位置和大小熊锭。通常這一行為也被稱(chēng)為“自動(dòng)重排”弧轧。
最后通過(guò)調(diào)用操作系統(tǒng) Native GUI 的 API 繪制雪侥。
4.2.4 API接口和RESTFul規(guī)范
1. 耦合架構(gòu)和前后端分離
在Vue和React框架出現(xiàn)之前,前端頁(yè)面的開(kāi)發(fā)都是由后端開(kāi)發(fā)人員來(lái)完成精绎,大部分頁(yè)面都是通過(guò)后端的模板渲染引擎(例如JSP速缨、PHP、Django)來(lái)完成的代乃,直到目前為止旬牲,依然有很多網(wǎng)站采用這樣的開(kāi)發(fā)方式。
這種開(kāi)發(fā)方式是采用耦合的架構(gòu)搁吓,所謂耦合原茅,也就是前后端開(kāi)發(fā)沒(méi)有分離,而是把數(shù)據(jù)和UI拼湊在了一起堕仔。采用這種方式的開(kāi)發(fā)具有以下缺點(diǎn):
后端開(kāi)發(fā)人員既要負(fù)責(zé)前端還要負(fù)責(zé)后端
如果數(shù)據(jù)結(jié)構(gòu)變化擂橘,需要修改模板以適應(yīng)數(shù)據(jù)變化
不專(zhuān)業(yè)的開(kāi)發(fā)人員很容易編寫(xiě)大量頁(yè)面造成項(xiàng)目無(wú)法維護(hù)
頁(yè)面的js文件編寫(xiě)隨意,依賴(lài)重復(fù)加載或忽略加載
因此摩骨,隨著技術(shù)的演進(jìn)通贞,前端和后端逐漸分離,形成了當(dāng)前大前端的趨勢(shì)恼五。前后端的數(shù)據(jù)交互昌罩,完全通過(guò)ajax來(lái)實(shí)現(xiàn),傳輸數(shù)據(jù)約定的規(guī)則就是采用RESTFul API灾馒。
采用這種方式開(kāi)發(fā)可以讓前端開(kāi)發(fā)人員只負(fù)責(zé)交互和渲染茎用,后端開(kāi)發(fā)人員只負(fù)責(zé)數(shù)據(jù)維護(hù)和生成,能夠有效進(jìn)行分工睬罗,這種開(kāi)發(fā)模式一般稱(chēng)為前后端分離绘搞。
2. API接口
API接口(Application Programming Interface,應(yīng)用程序接口)本身就是HTTP(S)協(xié)議的一部分傅物,它約定客戶(hù)端和服務(wù)器數(shù)據(jù)傳輸格式的形式夯辖。
下面就是一個(gè)API接口,但是僅僅只定義了一個(gè)地址董饰,卻沒(méi)有提供功能說(shuō)明和其他部分蒿褂。
https://www.npmjs.com/search?q=express
當(dāng)前的軟件開(kāi)發(fā)領(lǐng)域,API接口的定義規(guī)范主流的規(guī)則被稱(chēng)為RESTFul(Representational State Transfer卒暂,表述性狀態(tài)轉(zhuǎn)移)規(guī)范啄栓,了解了RESTFul規(guī)范就能熟悉整個(gè)API接口的規(guī)范了。
3. RESTFul規(guī)范
RESTFul規(guī)范大體遵循以下幾點(diǎn):
標(biāo)準(zhǔn)接口URL寫(xiě)法:協(xié)議://域名[:端口]/版本/路徑?過(guò)濾查詢(xún)也祠,URL結(jié)尾不應(yīng)該包含斜杠“/”昙楚,路徑中首選小寫(xiě)字母,路徑名詞均為復(fù)數(shù)诈嘿,端口號(hào)如果沒(méi)有輸入堪旧,表示80的默認(rèn)端口削葱。
如:
查詢(xún)分頁(yè)數(shù)據(jù),https://api.itcast.com/v1/books?page=0&size=10
查詢(xún)單條數(shù)據(jù):https://api.itcast.com/v1/books/id
對(duì)接口的操作淳梦,如獲取析砸、新建、更新爆袍、刪除首繁,需要在接口方法中指定,而不是在路徑中提供動(dòng)詞陨囊。
如:GET?https://api.itcast.com/v1/books?pageNum=0&pageSize=10
狀態(tài)碼:服務(wù)器返回的信息弦疮,成功與否必須通過(guò)狀態(tài)碼來(lái)確定,而不是放到response的body內(nèi)部蜘醋。如果狀態(tài)碼錯(cuò)誤胁塞,那么response的body中需要包含一個(gè)error字段來(lái)展示錯(cuò)誤信息。
返回的結(jié)果:
GET返回?cái)?shù)組或單個(gè)資源對(duì)象堂湖。
POST返回新生成的對(duì)象。
PUT状土、PATCH返回修改的對(duì)象
DELETE返回空對(duì)象无蜂。
4. 請(qǐng)求和響應(yīng)的Header
Header是HTTP的消息頭部,位于HTTP消息報(bào)頭部分蒙谓。雖然它不在RESTFul規(guī)范之內(nèi)斥季,但是它里面的信息非常重要,Header是由一堆鍵值對(duì)組成的配置信息累驮。由于HTTP協(xié)議分為請(qǐng)求和響應(yīng)兩部分酣倾,對(duì)于每個(gè)動(dòng)作,Header里面的配置會(huì)有一些區(qū)別谤专。
Header也可以添加自定義鍵值對(duì)躁锡,需要鍵名以X-開(kāi)頭,如X-Access-Token:xxx置侍,一般默認(rèn)的瀏覽器定義的Header無(wú)法手動(dòng)覆蓋和修改映之。
常用的HTTP請(qǐng)求Header
協(xié)議頭說(shuō)明示例狀態(tài)
Accept可接受的響應(yīng)內(nèi)容類(lèi)型(Content-Types)。Accept: text/plain固定
Accept-Charset可接受的字符集Accept-Charset: utf-8固定
Accept-Encoding可接受的響應(yīng)內(nèi)容的編碼方式蜡坊。Accept-Encoding: gzip, deflate固定
Accept-Language可接受的響應(yīng)內(nèi)容語(yǔ)言列表杠输。Accept-Language: en-US固定
Accept-Datetime可接受的按照時(shí)間來(lái)表示的響應(yīng)內(nèi)容版本Accept-Datetime: Sat, 26 Dec 2015 17:30:00 GMT臨時(shí)
Authorization用于表示HTTP協(xié)議中需要認(rèn)證資源的認(rèn)證信息Authorization: Basic OSdjJGRpbjpvcGVuIANlc2SdDE==固定
Cache-Control用來(lái)指定當(dāng)前的請(qǐng)求/回復(fù)中的,是否使用緩存機(jī)制秕衙。Cache-Control: no-cache固定
Connection客戶(hù)端(瀏覽器)想要優(yōu)先使用的連接類(lèi)型Connection: keep-alive固定
Cookie由之前服務(wù)器通過(guò)Set-Cookie(見(jiàn)下文)設(shè)置的一個(gè)HTTP協(xié)議CookieCookie: $Version=1; Skin=new;固定:標(biāo)準(zhǔn)
Content-Length以8進(jìn)制表示的請(qǐng)求體的長(zhǎng)度Content-Length: 348固定
Content-MD5請(qǐng)求體的內(nèi)容的二進(jìn)制 MD5 散列值(數(shù)字簽名)蠢甲,以 Base64 編碼的結(jié)果Content-MD5: oD8dH2sgSW50ZWdyaIEd9D==廢棄
Content-Type請(qǐng)求體的MIME類(lèi)型 (用于POST和PUT請(qǐng)求中)Content-Type: application/x-www-form-urlencoded固定
Date發(fā)送該消息的日期和時(shí)間(以RFC 7231中定義的"HTTP日期"格式來(lái)發(fā)送)Date: Dec, 26 Dec 2015 17:30:00 GMT固定
Expect表示客戶(hù)端要求服務(wù)器做出特定的行為Expect: 100-continue固定
From發(fā)起此請(qǐng)求的用戶(hù)的郵件地址From: user@itbilu.com固定
Host表示服務(wù)器的域名以及服務(wù)器所監(jiān)聽(tīng)的端口號(hào)。如果所請(qǐng)求的端口是對(duì)應(yīng)的服務(wù)的標(biāo)準(zhǔn)端口(80)据忘,則端口號(hào)可以省略鹦牛。Host: www.itbilu.com:8080固定
If-Match僅當(dāng)客戶(hù)端提供的實(shí)體與服務(wù)器上對(duì)應(yīng)的實(shí)體相匹配時(shí)搞糕,才進(jìn)行對(duì)應(yīng)的操作。主要用于像 PUT 這樣的方法中能岩,僅當(dāng)從用戶(hù)上次更新某個(gè)資源后寞宫,該資源未被修改的情況下,才更新該資源拉鹃。If-Match: "9jd00cdj34pss9ejqiw39d82f20d0ikd"固定
If-Modified-Since允許在對(duì)應(yīng)的資源未被修改的情況下返回304未修改If-Modified-Since: Dec, 26 Dec 2015 17:30:00 GMT固定
If-None-Match允許在對(duì)應(yīng)的內(nèi)容未被修改的情況下返回304未修改( 304 Not Modified )辈赋,參考 超文本傳輸協(xié)議 的實(shí)體標(biāo)記If-None-Match: "9jd00cdj34pss9ejqiw39d82f20d0ikd"固定
If-Range如果該實(shí)體未被修改過(guò),則向返回所缺少的那一個(gè)或多個(gè)部分膏燕。否則钥屈,返回整個(gè)新的實(shí)體If-Range: "9jd00cdj34pss9ejqiw39d82f20d0ikd"固定
If-Unmodified-Since僅當(dāng)該實(shí)體自某個(gè)特定時(shí)間以來(lái)未被修改的情況下,才發(fā)送回應(yīng)坝辫。If-Unmodified-Since: Dec, 26 Dec 2015 17:30:00 GMT固定
Max-Forwards限制該消息可被代理及網(wǎng)關(guān)轉(zhuǎn)發(fā)的次數(shù)篷就。Max-Forwards: 10固定
Origin發(fā)起一個(gè)針對(duì)跨域資源共享的請(qǐng)求(該請(qǐng)求要求服務(wù)器在響應(yīng)中加入一個(gè)Access-Control-Allow-Origin的消息頭,表示訪問(wèn)控制所允許的來(lái)源)近忙。Origin: http://www.itbilu.com固定: 標(biāo)準(zhǔn)
Pragma與具體的實(shí)現(xiàn)相關(guān)竭业,這些字段可能在請(qǐng)求/回應(yīng)鏈中的任何時(shí)候產(chǎn)生。Pragma: no-cache固定
Proxy-Authorization用于向代理進(jìn)行認(rèn)證的認(rèn)證信息及舍。Proxy-Authorization: Basic IOoDZRgDOi0vcGVuIHNlNidJi2==固定
Range表示請(qǐng)求某個(gè)實(shí)體的一部分未辆,字節(jié)偏移以0開(kāi)始。Range: bytes=500-999固定
Referer表示瀏覽器所訪問(wèn)的前一個(gè)頁(yè)面锯玛,可以認(rèn)為是之前訪問(wèn)頁(yè)面的鏈接將瀏覽器帶到了當(dāng)前頁(yè)面咐柜。Referer其實(shí)是Referrer這個(gè)單詞,但RFC制作標(biāo)準(zhǔn)時(shí)給拼錯(cuò)了攘残,后來(lái)也就將錯(cuò)就錯(cuò)使用Referer了拙友。Referer:?http://itbilu.com/nodejs固定
TE瀏覽器預(yù)期接受的傳輸時(shí)的編碼方式:可使用回應(yīng)協(xié)議頭Transfer-Encoding中的值(還可以使用"trailers"表示數(shù)據(jù)傳輸時(shí)的分塊方式)用來(lái)表示瀏覽器希望在最后一個(gè)大小為0的塊之后還接收到一些額外的字段。TE: trailers,deflate固定
User-Agent瀏覽器的身份標(biāo)識(shí)字符串User-Agent: Mozilla/……固定
Upgrade要求服務(wù)器升級(jí)到一個(gè)高版本協(xié)議歼郭。Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11固定
Via告訴服務(wù)器遗契,這個(gè)請(qǐng)求是由哪些代理發(fā)出的。Via: 1.0 fred, 1.1 itbilu.com.com (Apache/1.1)固定
Warning一個(gè)一般性的警告病曾,表示在實(shí)體內(nèi)容體中可能存在錯(cuò)誤姊途。Warning: 199 Miscellaneous warning固定
常用的HTTP響應(yīng)頭
響應(yīng)頭說(shuō)明示例狀態(tài)
Access-Control-Allow-Origin指定哪些網(wǎng)站可以跨域源資源共享Access-Control-Allow-Origin: *臨時(shí)
Accept-Patch指定服務(wù)器所支持的文檔補(bǔ)丁格式Accept-Patch: text/example;charset=utf-8固定
Accept-Ranges服務(wù)器所支持的內(nèi)容范圍Accept-Ranges: bytes固定
Age響應(yīng)對(duì)象在代理緩存中存在的時(shí)間,以秒為單位Age: 12固定
Allow對(duì)于特定資源的有效動(dòng)作;Allow: GET, HEAD固定
Cache-Control通知從服務(wù)器到客戶(hù)端內(nèi)的所有緩存機(jī)制知态,表示它們是否可以緩存這個(gè)對(duì)象及緩存有效時(shí)間捷兰。其單位為秒Cache-Control: max-age=3600固定
Connection針對(duì)該連接所預(yù)期的選項(xiàng)Connection: close固定
Content-Disposition對(duì)已知MIME類(lèi)型資源的描述,瀏覽器可以根據(jù)這個(gè)響應(yīng)頭決定是對(duì)返回資源的動(dòng)作负敏,如:將其下載或是打開(kāi)贡茅。Content-Disposition: attachment; filename="fname.ext"固定
Content-Encoding響應(yīng)資源所使用的編碼類(lèi)型。Content-Encoding: gzip固定
Content-Language響就內(nèi)容所使用的語(yǔ)言Content-Language: zh-cn固定
Content-Length響應(yīng)消息體的長(zhǎng)度,用8進(jìn)制字節(jié)表示Content-Length: 348固定
Content-Location所返回的數(shù)據(jù)的一個(gè)候選位置Content-Location: /index.htm固定
Content-MD5響應(yīng)內(nèi)容的二進(jìn)制 MD5 散列值顶考,以 Base64 方式編碼Content-MD5: IDK0iSsgSW50ZWd0DiJUi==已淘汰
Content-Range如果是響應(yīng)部分消息赁还,表示屬于完整消息的哪個(gè)部分Content-Range: bytes 21010-47021/47022固定
Content-Type當(dāng)前內(nèi)容的MIME類(lèi)型Content-Type: text/html; charset=utf-8固定
Date此條消息被發(fā)送時(shí)的日期和時(shí)間(以RFC 7231中定義的"HTTP日期"格式來(lái)表示)Date: Tue, 15 Nov 1994 08:12:31 GMT固定
ETag對(duì)于某個(gè)資源的某個(gè)特定版本的一個(gè)標(biāo)識(shí)符,通常是一個(gè) 消息散列ETag: "737060cd8c284d8af7ad3082f209582d"固定
Expires指定一個(gè)日期/時(shí)間驹沿,超過(guò)該時(shí)間則認(rèn)為此回應(yīng)已經(jīng)過(guò)期Expires: Thu, 01 Dec 1994 16:00:00 GMT固定: 標(biāo)準(zhǔn)
Last-Modified所請(qǐng)求的對(duì)象的最后修改日期(按照 RFC 7231 中定義的“超文本傳輸協(xié)議日期”格式來(lái)表示)Last-Modified: Dec, 26 Dec 2015 17:30:00 GMT固定
Link用來(lái)表示與另一個(gè)資源之間的類(lèi)型關(guān)系艘策,此類(lèi)型關(guān)系是在RFC 5988中定義Link:; rel="alternate"固定
Location用于在進(jìn)行重定向,或在創(chuàng)建了某個(gè)新資源時(shí)使用渊季。Location:?http://www.itbilu.com/nodejs固定
P3PP3P策略相關(guān)設(shè)置P3P: CP="This is not a P3P policy!固定
Pragma與具體的實(shí)現(xiàn)相關(guān)朋蔫,這些響應(yīng)頭可能在請(qǐng)求/回應(yīng)鏈中的不同時(shí)候產(chǎn)生不同的效果Pragma: no-cache固定
Proxy-Authenticate要求在訪問(wèn)代理時(shí)提供身份認(rèn)證信息。Proxy-Authenticate: Basic固定
Public-Key-Pins用于防止中間攻擊却汉,聲明網(wǎng)站認(rèn)證中傳輸層安全協(xié)議的證書(shū)散列值Public-Key-Pins: max-age=2592000; pin-sha256="……";固定
Refresh用于重定向驯妄,或者當(dāng)一個(gè)新的資源被創(chuàng)建時(shí)。默認(rèn)會(huì)在5秒后刷新重定向合砂。Refresh: 5; url=http://itbilu.com
Retry-After如果某個(gè)實(shí)體臨時(shí)不可用青扔,那么此協(xié)議頭用于告知客戶(hù)端稍后重試。其值可以是一個(gè)特定的時(shí)間段(以秒為單位)或一個(gè)超文本傳輸協(xié)議日期翩伪。示例1:Retry-After: 120示例2: Retry-After: Dec, 26 Dec 2015 17:30:00 GMT固定
Server服務(wù)器的名稱(chēng)Server: nginx/1.6.3固定
Set-Cookie設(shè)置HTTP cookieSet-Cookie: UserID=itbilu; Max-Age=3600; Version=1固定: 標(biāo)準(zhǔn)
Status通用網(wǎng)關(guān)接口的響應(yīng)頭字段微猖,用來(lái)說(shuō)明當(dāng)前HTTP連接的響應(yīng)狀態(tài)。Status: 200 OK
TrailerTrailer用戶(hù)說(shuō)明傳輸中分塊編碼的編碼信息Trailer: Max-Forwards固定
Transfer-Encoding用表示實(shí)體傳輸給用戶(hù)的編碼形式缘屹。包括:chunked凛剥、compress、 deflate囊颅、gzip当悔、identity傅瞻。Transfer-Encoding: chunked固定
Upgrade要求客戶(hù)端升級(jí)到另一個(gè)高版本協(xié)議踢代。Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11固定
Vary告知下游的代理服務(wù)器,應(yīng)當(dāng)如何對(duì)以后的請(qǐng)求協(xié)議頭進(jìn)行匹配嗅骄,以決定是否可使用已緩存的響應(yīng)內(nèi)容而不是重新從原服務(wù)器請(qǐng)求新的內(nèi)容胳挎。Vary: *固定
Via告知代理服務(wù)器的客戶(hù)端,當(dāng)前響應(yīng)是通過(guò)什么途徑發(fā)送的溺森。Via: 1.0 fred, 1.1 itbilu.com (nginx/1.6.3)固定
Warning一般性警告慕爬,告知在實(shí)體內(nèi)容體中可能存在錯(cuò)誤。Warning: 199 Miscellaneous warning固定
WWW-Authenticate表示在請(qǐng)求獲取這個(gè)實(shí)體時(shí)應(yīng)當(dāng)使用的認(rèn)證模式屏积。WWW-Authenticate: Basic固定
Header中的Content-Type
Content-Type表示請(qǐng)求或響應(yīng)的數(shù)據(jù)類(lèi)型医窿。
其格式是type/subType;charset;boundary
type:subType:主類(lèi)型/次類(lèi)型,如text/html炊林,application/json姥卢。
charset,字符編碼標(biāo)準(zhǔn),一般是utf-8独榴。
boundary僧叉,用于分隔請(qǐng)求主體的字段分隔符。
常用的用于請(qǐng)求的有如下幾個(gè)
application/x-www-form-urlencoded: 數(shù)據(jù)被編碼成以 '&' 分隔的鍵-值對(duì), 同時(shí)以 '=' 分隔鍵和值. 非字母或數(shù)字的字符會(huì)被轉(zhuǎn)碼棺榔,不要用于文件等二進(jìn)制數(shù)據(jù)瓶堕。在POST中會(huì)放到body中,在GET中會(huì)追加到URL后面症歇。express的body-parser通過(guò)urlencoded方法來(lái)解析郎笆。
application/x-www-form-urlencoded請(qǐng)求的主體內(nèi)容
POST / HTTP/1.1
Content-Type:application/x-www-form-urlencoded//指定了類(lèi)型
Accept-Encoding: gzip, deflate
Host: w.sohu.com
Content-Length: 21//content內(nèi)容長(zhǎng)度
Connection: Keep-Alive
Cache-Control: no-cache// 下面是一條空行隔開(kāi)的內(nèi)容,然后是被格式化的請(qǐng)求參數(shù)当船。
txt1=hello&txt2=world
multipart/form-data:在application/x-www-form-urlencoded的基礎(chǔ)上支持文件上傳题画,但body中的內(nèi)容會(huì)更多,所以如果沒(méi)有文件德频,不建議用這個(gè)苍息。
boundary用來(lái)告訴服務(wù)器從哪里分隔主體內(nèi)容。
multipart/form-data請(qǐng)求的主體內(nèi)容
POST /t2/upload.do HTTP/1.1
User-Agent: SOHUWapRebot
Accept-Language: zh-cn,zh;q=0.5
Accept-Charset: GBK,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Content-Length: 60408
// boundary用來(lái)告訴服務(wù)器從哪里分隔主體內(nèi)容
// multipart/form-data的數(shù)據(jù)主體很明顯是把每一個(gè)字段都做了細(xì)致的描述壹置,如每個(gè)字段還可以包含Content-Disposition竞思,Content-Type,Content-Transfer-Encoding屬性描述钞护,來(lái)告訴服務(wù)器如何解析這個(gè)字段盖喷,因此會(huì)顯著增大傳輸?shù)膬?nèi)容容量。
Content-Type:multipart/form-data; boundary=ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC
Host: w.sohu.com
--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC
Content-Disposition: form-data; name="city"
Santa colo
--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC
Content-Disposition: form-data;name="desc"
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
...
--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC
Content-Disposition: form-data;name="pic"; filename="photo.jpg"
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
... binary data of the jpg ...
--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC--
application/json:支持序列化的json(JSON.stringify)难咕,序列化的json可以存儲(chǔ)更復(fù)雜的鍵值對(duì)嵌套結(jié)構(gòu)课梳,包括數(shù)組、Date等的原生轉(zhuǎn)換余佃。
POST http://www.example.com HTTP/1.1
Content-Type: application/json;charset=utf-8
{"title":"test","sub":[1,2,3]}
text/plain:傳遞的數(shù)據(jù)就是純文本暮刃,服務(wù)器不做任何處理。
text/html:傳遞的數(shù)據(jù)會(huì)被解析成html爆土。
5. 接口測(cè)試工具
Postman
Postman是一個(gè)非常好用的API調(diào)試工具椭懊,通過(guò)這個(gè)工具可以任意指定和查看HTTP請(qǐng)求的Header(包括Content-Type)、方法以及請(qǐng)求數(shù)據(jù)步势,而且能夠?qū)?shù)據(jù)進(jìn)行格式化氧猬。在測(cè)試服務(wù)器接口的時(shí)候,這個(gè)工具能夠讓我們快速的預(yù)覽和調(diào)試接口坏瘩。
Chrome -> 開(kāi)發(fā)者工具 -> NetWork
除了使用第三方工具盅抚,瀏覽器一般在開(kāi)發(fā)者工具中也集成了接口調(diào)試,在其中可以查看接口請(qǐng)求的所有信息倔矾。
Swagger
Swagger是一個(gè)API接口文檔生成工具妄均,除了能夠根據(jù)annotation生成API文檔之外,自動(dòng)生成的文檔中還可以測(cè)試每個(gè)接口。
安裝
npm install --save swagger-ui-express
編寫(xiě)一個(gè)符合swagger規(guī)范的API文檔丛晦,規(guī)范格式參考swagger editor奕纫。命名為swagger.json,放到工程根目錄下烫沙。
{
? ? "swagger": "2.0",
? ? "info": {
? ? ? ? "description": "這是一個(gè)測(cè)試的API文檔,你可以使用**Markdown語(yǔ)法**",
? ? ? ? "version": "1.0.0",
? ? ? ? "title": "API文檔",
? ? ? ? "contact": {
? ? ? ? ? ? "email": "apiteam@swagger.io"
? ? ? ? }
? ? },
? ? "host": "localhost:3000",
? ? "basePath": "/v1",
? ? "tags": [
? ? ? ? {
? ? ? ? ? ? "name": "user",
? ? ? ? ? ? "description": "用戶(hù)操作",
? ? ? ? ? ? "externalDocs": {
? ? ? ? ? ? ? ? "description": "更多信息請(qǐng)見(jiàn)",
? ? ? ? ? ? ? ? "url": "http://swagger.io"
? ? ? ? ? ? }
? ? ? ? }
? ? ],
? ? "schemes": [
? ? ? ? "https",
? ? ? ? "http"
? ? ],
? ? "paths": {
? ? ? ? "/user": {
? ? ? ? ? ? "post": {
? ? ? ? ? ? ? ? "tags": [
? ? ? ? ? ? ? ? ? ? "user"
? ? ? ? ? ? ? ? ],
? ? ? ? ? ? ? ? "summary": "添加用戶(hù)",
? ? ? ? ? ? ? ? "description": "",
? ? ? ? ? ? ? ? "operationId": "addPet",
? ? ? ? ? ? ? ? "consumes": [
? ? ? ? ? ? ? ? ? ? "application/json",
? ? ? ? ? ? ? ? ? ? "application/xml"
? ? ? ? ? ? ? ? ],
? ? ? ? ? ? ? ? "produces": [
? ? ? ? ? ? ? ? ? ? "application/xml",
? ? ? ? ? ? ? ? ? ? "application/json"
? ? ? ? ? ? ? ? ],
? ? ? ? ? ? ? ? "parameters": [
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? "in": "body",
? ? ? ? ? ? ? ? ? ? ? ? "name": "name",
? ? ? ? ? ? ? ? ? ? ? ? "description": "用戶(hù)的名字",
? ? ? ? ? ? ? ? ? ? ? ? "required": true
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ],
? ? ? ? ? ? ? ? "responses": {
? ? ? ? ? ? ? ? ? ? "405": {
? ? ? ? ? ? ? ? ? ? ? ? "description": "非法輸入"
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
修改index.js代碼
const express = require('express')
const swaggerUi = require('swagger-ui-express')
const app = express()
const swaggerDocument = require('./swagger.json');
// 訪問(wèn)api地址可以查看api
app.use('/api', swaggerUi.serve, swaggerUi.setup(swaggerDocument))
app.listen(3000, () => {
? ? console.log('服務(wù)器創(chuàng)建完畢,監(jiān)聽(tīng)3000端口')
})
執(zhí)行index.js
node index.js
瀏覽器打開(kāi)http://localhost:3000/api?即可查看效果匹层。
點(diǎn)擊user一欄,會(huì)展開(kāi)锌蓄,點(diǎn)擊Try it out即可測(cè)試接口數(shù)據(jù)升筏。
4.3 Express常用中間件
了解了服務(wù)器和客戶(hù)端的通信原理,接下來(lái)我們就可以使用Express來(lái)編寫(xiě)自己Web應(yīng)用的接口了瘸爽。Express編寫(xiě)業(yè)務(wù)邏輯大部分都是基于中間件去實(shí)現(xiàn)的您访,中間件封裝了一些特定的邏輯,輔助我們可以快速的開(kāi)發(fā)剪决。
4.3.1 什么是中間件
Express 是一個(gè)路由和中間件 Web 框架灵汪,其自身只具有最低程度的功能:Express 應(yīng)用程序基本上是一系列中間件函數(shù)調(diào)用。
Express 應(yīng)用程序可以使用以下類(lèi)型的中間件: