1.1導(dǎo)學(xué)開(kāi)始
數(shù)據(jù)內(nèi)容傳輸都是通過(guò)http協(xié)議的妆兑。
需要理解http
http很重要
提升自身價(jià)值
簡(jiǎn)單的例子:瀏覽器中輸入網(wǎng)頁(yè)蔓纠,ajax數(shù)據(jù)邻眷,img加載圖片
Cache-Control鼓鲁?
緩存的驗(yàn)證
深入到TCP
Nginx使用
準(zhǔn)備:http這個(gè)概念
1.2內(nèi)容介紹
2.1五層網(wǎng)絡(luò)模型介紹
一翎嫡、經(jīng)典五層模型
1臀突、應(yīng)用層:為應(yīng)用軟件提供了很多服務(wù)勉抓,構(gòu)建于tcp協(xié)議之上,屏蔽網(wǎng)絡(luò)傳輸相關(guān)細(xì)節(jié)候学。
(1)http琳状,ftp…
2、傳輸層:向用戶(hù)提供可靠的端到端(end-to-end)服務(wù)
(1)如tcp盒齿,udp
(2)傳輸層向高層屏蔽了下層數(shù)據(jù)通信的細(xì)節(jié)
————底三層————
3念逞、網(wǎng)絡(luò)層:為數(shù)據(jù)在結(jié)點(diǎn)之間傳輸創(chuàng)建邏輯鏈路。
4边翁、數(shù)據(jù)鏈路層:在通信的實(shí)體間建立數(shù)據(jù)鏈路連接翎承。
5、物理層:定義物理設(shè)備如何傳輸數(shù)據(jù)符匾。
(1)如電腦硬件叨咖,網(wǎng)卡端口,網(wǎng)線,光纜甸各。
2.2HTTP協(xié)議的發(fā)展歷史
HTTP/0.9
只有一個(gè)Get命令
沒(méi)有Header等描述數(shù)據(jù)的信息
服務(wù)器發(fā)送完畢垛贤,就關(guān)閉TCP連接
HTTP/1.0
增加了很多命令
增加了status code和header
多字符集支持、多部分發(fā)送趣倾、權(quán)限聘惦、緩存等
HTTP/1.1
持久連接
pipeline
增加host和其他一些命令
HTTP2
所有數(shù)據(jù)以二進(jìn)制傳輸
同一個(gè)連接里面發(fā)送多個(gè)請(qǐng)求不再需要按照順序來(lái)
頭信息壓縮以及推送等提高效率的功能
2.3HTTP的三次握手
一、tcp connection
1儒恋、http只有請(qǐng)求和響應(yīng)的概念善绎,沒(méi)有連接的概念,靠tcp來(lái)連接請(qǐng)求诫尽。
2禀酱、一個(gè)tcp連接可以發(fā)送多個(gè)http請(qǐng)求。1.0請(qǐng)求發(fā)送就會(huì)就斷開(kāi)了牧嫉,1.1保持連接剂跟,減少Tcp開(kāi)銷(xiāo),只要開(kāi)一個(gè)TCP連接酣藻。
3浩聋、三次握手
(1)防止服務(wù)器開(kāi)啟一些無(wú)用的連接
二、wireshark抓包:網(wǎng)絡(luò)層臊恋、tcp層衣洁、http層都可以抓到
charles是抓到http層
2.4 URI、URL抖仅、URN
1坊夫、Uniform Resource Identifier 統(tǒng)一資源標(biāo)識(shí)符
2、用來(lái)唯一標(biāo)識(shí)互聯(lián)網(wǎng)上的信息資源
3撤卢、包含URL环凿、URN
二、URL
1放吩、Uniform Resource Locator 統(tǒng)一資源定位符
2智听、http://user:pass@host.com:80/path?query=string#hash
3、此類(lèi)格式的都叫做url渡紫,比如ftp協(xié)議到推、 file
protocol :// hostname[:port] / path / [;parameters][?query]#fragment
protocol(協(xié)議)
指定使用的傳輸協(xié)議,下表列出 protocol 屬性的有效方案名稱(chēng)惕澎。 最常用的是HTTP協(xié)議莉测,它也是目前WWW中應(yīng)用最廣的協(xié)議。
file 資源是本地計(jì)算機(jī)上的文件唧喉。格式file:///捣卤,注意后邊應(yīng)是三個(gè)斜杠忍抽。
ftp 通過(guò) FTP訪問(wèn)資源。格式 FTP://
http 通過(guò) HTTP 訪問(wèn)該資源董朝。 格式 HTTP://
https 通過(guò)安全的 HTTPS 訪問(wèn)該資源鸠项。 格式 HTTPS://
hostname(主機(jī)名)
是指存放資源的服務(wù)器的域名系統(tǒng)(DNS) 主機(jī)名或 IP 地址。有時(shí)子姜,在主機(jī)名前也可以包含連接到服務(wù)器所需的用戶(hù)名和密碼(格式:username:password@hostname)祟绊。
port(端口號(hào))
整數(shù),可選闲询,省略時(shí)使用方案的默認(rèn)端口久免,各種傳輸協(xié)議都有默認(rèn)的端口號(hào)浅辙,如http的默認(rèn)端口為80扭弧。如果輸入時(shí)省略,則使用默認(rèn)端口號(hào)记舆。有時(shí)候出于安全或其他考慮鸽捻,可以在服務(wù)器上對(duì)端口進(jìn)行重定義,即采用非標(biāo)準(zhǔn)端口號(hào)泽腮,此時(shí)御蒲,URL中就不能省略端口號(hào)這一項(xiàng)。
path(路徑)
由零或多個(gè)“/”符號(hào)隔開(kāi)的字符串诊赊,一般用來(lái)表示主機(jī)上的一個(gè)目錄或文件地址厚满。
parameters(參數(shù))
這是用于指定特殊參數(shù)的可選項(xiàng)。
query(查詢(xún))
可選碧磅,用于給動(dòng)態(tài)網(wǎng)頁(yè)(如使用CGI碘箍、ISAPI、PHP/JSP/ASP/ASP鲸郊。NET等技術(shù)制作的網(wǎng)頁(yè))傳遞參數(shù)丰榴,可有多個(gè)參數(shù),用“&”符號(hào)隔開(kāi)秆撮,每個(gè)參數(shù)的名和值用“=”符號(hào)隔開(kāi)四濒。
fragment(信息片斷)
字符串,用于指定網(wǎng)絡(luò)資源中的片斷职辨。例如一個(gè)網(wǎng)頁(yè)中有多個(gè)名詞解釋?zhuān)墒褂胒ragment直接定位到某一名詞解釋
三盗蟆、URN
1、Uniform Resource Name舒裤,永久統(tǒng)一資源定位符
2姆涩、在資源移動(dòng)之后還能被找到
3、目前還沒(méi)有非常成熟的使用方案惭每。
2.5http報(bào)文格式
報(bào)文主要分為起始行骨饿、首部亏栈、主體。
起始行
在請(qǐng)求報(bào)文中宏赘,起始行包含了HTTP的Method绒北、路由地址和HTTP協(xié)議版本,在響應(yīng)報(bào)文中則是HTTP協(xié)議版本和Status Code如上圖
首部:后續(xù)詳細(xì)講
主體
HTTP請(qǐng)求中返回的內(nèi)容察署。
HTTP方法
用來(lái)定義對(duì)資源的操作
常用有GET闷游、POST等
從定義上講有各自的語(yǔ)義
HTTP CODE,定義服務(wù)器對(duì)請(qǐng)求的處理結(jié)果
各個(gè)區(qū)間的CODE有各自的語(yǔ)義贴汪,
如100-199之間代表這個(gè)操作需要持續(xù)的進(jìn)行脐往,
200-299之間代表操作是成功的,
300-399之間代表重定向扳埂,
400-499之間代表發(fā)送的請(qǐng)求有問(wèn)題业簿,
500-599之間代表服務(wù)器出現(xiàn)了錯(cuò)誤。
好的HTTP服務(wù)可以通過(guò)CODE判斷結(jié)果
2.6 實(shí)現(xiàn)一個(gè)最簡(jiǎn)單的http服務(wù)(nodejs)
const http = require('http')
http.createServer(function (request, response) {
console.log('request come', request.url)
response.end('123')
}).listen('2333')
console.log('server listening on 2333')
3.1認(rèn)識(shí)http客戶(hù)端
一阳懂、瀏覽器是最常用的http客戶(hù)端
二梅尤、查看http請(qǐng)求, terminal
1、curl baidu.com岩调。curl只是發(fā)送請(qǐng)求巷燥,并返回,不會(huì)對(duì)頁(yè)面進(jìn)行渲染
2号枕、curl www.baidu.com
3缰揪、curl -v www.baidu.com
可以看到dns解析后的ip地址。
3.2跨域請(qǐng)求的限制與解決
跨域:指的是瀏覽器不能執(zhí)行其他網(wǎng)站的腳本葱淳。它是由瀏覽器的同源策略造成的钝腺,是瀏覽器施加的安全限制。
所謂同源是指蛙紫,協(xié)議拍屑、域名、端口均相同坑傅,不明白沒(méi)關(guān)系僵驰,舉個(gè)栗子:
http://www.123.com/index.html 調(diào)用 http://www.123.com/server.php (非跨域)
http://www.123.com/index.html 調(diào)用 http://www.456.com/server.php (主域名不同:123/456,跨域)
http://abc.123.com/index.html 調(diào)用 http://def.123.com/server.php (子域名不同:abc/def唁毒,跨域)
http://www.123.com:8080/index.html 調(diào)用 http://www.123.com:8081/server.php (端口不同:8080/8081蒜茴,跨域)
http://www.123.com/index.html 調(diào)用 https://www.123.com/server.php (協(xié)議不同:http/https,跨域)
請(qǐng)注意:localhost和127.0.0.1雖然都指向本機(jī)浆西,但也屬于跨域
那么該如何解決跨域問(wèn)題呢
JSONP使用方式
<script src="需要請(qǐng)求的地址">
</script>
但是要注意JSONP只支持GET請(qǐng)求粉私,不支持POST請(qǐng)求。
添加請(qǐng)求頭
還是用Node環(huán)境進(jìn)行測(cè)試近零,在當(dāng)前目錄下有server.js,server2.js,index.html诺核。
貼上server.js(請(qǐng)求方)的代碼
const http = require('http')
const fs = require('fs')
http.createServer(function (request, response) {
console.log('request come', request.url)
const html = fs.readFileSync('index.html', 'utf8')
response.writeHead(200, {
'Content-Type': 'text/html'
})
response.end(html)
}).listen('2333')
console.log('server listening on 2333')
server2.js(響應(yīng)方)代碼
const http = require('http')
http.createServer(function (request, response) {
console.log('request come', request.url)
response.writeHead(200, {
'Access-Control-Allow-Origin': '*'
})
response.end('123')
}).listen('2334')
console.log('server listening on 2334')
index.html的代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
</body>
<script>
var xhr = new XMLHttpRequest()
xhr.open('GET', 'http://127.0.0.1:2334/')
xhr.send()
</script>
</html>
新建兩個(gè)終端分別運(yùn)行node server.js抄肖,node server2.js,打開(kāi)localhost:2333窖杀,可以看到漓摩,我們當(dāng)前從不同端口請(qǐng)求時(shí),是屬于跨域請(qǐng)求的入客,但是并沒(méi)有跨域的報(bào)錯(cuò)管毙,原因是因?yàn)槲覀冊(cè)陧憫?yīng)方里添加了請(qǐng)求頭'Access-Control-Allow-Origin': '*',如果去掉了這個(gè)請(qǐng)求頭的話桌硫,則會(huì)報(bào)錯(cuò)
代理:
例如 www.123.com/index.html需要調(diào)用www.456.com/server.php夭咬,可以寫(xiě)一個(gè)接口www.123.com/server.php,由這個(gè)接口在后端去調(diào)用www.456.com/server.php并拿到返回值铆隘,然后再返回給index.html卓舵,這就是一個(gè)代理的模式。相當(dāng)于繞過(guò)了瀏覽器端咖驮,自然就不存在跨域問(wèn)題
3.3CORS跨域限制以及預(yù)請(qǐng)求驗(yàn)證
1边器、首先要說(shuō)一下CORS跨域的限制训枢,CORS允許的方法只有
GET HEAD POST
2托修、CORS允許的Content-Type只有
text/plain
multipart/form-data
application/x-www-form-urlencoded`
其他限制:請(qǐng)求頭限制、XMLHttpRequestUpload對(duì)象均沒(méi)有注冊(cè)任何事件監(jiān)聽(tīng)器恒界、請(qǐng)求中沒(méi)有使用ReadableStream對(duì)象
假如我們使用fetch預(yù)請(qǐng)求睦刃,并需要帶一個(gè)自定義的請(qǐng)求頭如:X-Test-Cors,那么必須要在服務(wù)端中定義好Access-Control-Allow-Headers: X-Test-Cors十酣,否則則會(huì)報(bào)錯(cuò)涩拙。
同理,如果我們需要使用其他自定義的方法的話耸采,我們同樣需要在服務(wù)端中定義Access-Control-Allow-Methods: Post, Put, Delete, xxxxxxx
3.4緩存頭Cache-Control
1兴泥、可緩存性
public:代表http請(qǐng)求經(jīng)過(guò)的任何地方(代理服務(wù)器等等)都可以進(jìn)行緩存。
private:代表只有發(fā)起請(qǐng)求的瀏覽器才可以進(jìn)行緩存
no-cache:任何節(jié)點(diǎn)都不可以進(jìn)行緩存
2虾宇、到期
緩存到期時(shí)間:max-age = <seconds>(秒)
代理服務(wù)器使用:s-maxage = <seconds>(秒)
指示客戶(hù)機(jī)可以接收超出max-age時(shí)間的響應(yīng)消息搓彻,max-stale在請(qǐng)求設(shè)置中有效,在響應(yīng)設(shè)置中無(wú)效:`max-stale =
3嘱朽、重新驗(yàn)證
must-revalidate:如果過(guò)期旭贬,則必須更新
proxy-revalidate
和must-revalidate差不多,是給緩存服務(wù)器使用的搪泳。
4稀轨、其他
no-store
no-cache從字面意義上很容易誤解為不緩存,但是no-cache代表不緩存過(guò)期的資源岸军,緩存會(huì)向服務(wù)器進(jìn)行有效處理確認(rèn)之后處理資源奋刽,更確切的說(shuō)瓦侮,no-cache應(yīng)該是:do-not-serve-from-cache-without-revalidation
而no-store才是真正的不進(jìn)行緩存
使用no-cache的目的就是為了防止從緩存中獲取過(guò)期的資源。
no-transform
如果第三方網(wǎng)站不希望頁(yè)面轉(zhuǎn)碼佣谐,可在頁(yè)面中添加此協(xié)議脏榆,當(dāng)用戶(hù)進(jìn)入時(shí),會(huì)直接跳轉(zhuǎn)至原網(wǎng)頁(yè)
具體實(shí)踐:Cache-Control緩存到期時(shí)間
const http = require('http')
const fs = require('fs')
http.createServer(function (request, response) {
console.log('request come --- ', request.url)
if (request.url === '/') {
const html = fs.readFileSync('test.html', 'utf8')
response.writeHead(200, {
'Content-Type': 'text/html'
})
response.end(html)
}
if (request.url === '/script.js') {
response.writeHead(200, {
'Content-Type': 'text/javascript',
'Cache-Control': 'max-age=200'
})
response.end('console.log("script loaded")')
}
}).listen('8888')
console.log('server listening on 8888')
加入了Cache-Control': 'max-age=200'之后台谍,瀏覽器(客戶(hù)端)即可對(duì)靜態(tài)資源進(jìn)行緩存须喂,效果如下圖所示。過(guò)了200秒后趁蕊,緩存失效坞生,
3.5緩存驗(yàn)證Last-Modified和Etag
一、Last-Modified
1掷伙、上次修改時(shí)間是己,配合If-Modified-Since或者If-Unmodified-Since使用。
2任柜、對(duì)比上次修改時(shí)間以驗(yàn)證資源是否需要更新卒废。
二、Etag
1宙地、數(shù)據(jù)簽名
2摔认、最常見(jiàn)的:對(duì)資源進(jìn)行hash計(jì)算
3、對(duì)比資源的簽名判斷是否使用緩存
server.js
const http = require('http')
const fs = require('fs')
http.createServer(function (request, response) {
console.log('request come --- ', request.url)
const etag = request.headers['if-none-match'];
if (etag === '777') {
response.writeHead(304, {
'Content-Type': 'text/javascript',
'Cache-Control': 'max-age=200000, no-cache',
'Last-Modified': '123',
'Etag': '777'
})
response.writeHead()
} else {
response.writeHead(200, {
'Content-Type': 'text/javascript',
'Cache-Control': 'max-age=200000, no-cache',
'Last-Modified': '123',
'Etag': '777'
})
response.end('console.log("scripte loaded twice")')
}
}).listen('8888')
console.log('server listening on 8888')
index.html
3.6 cookie和session
1宅粥、Cookie
通過(guò)Set-Cookie設(shè)置
下次請(qǐng)求會(huì)自動(dòng)帶上
鍵值對(duì)参袱,可以設(shè)置多個(gè)
2、Cookie屬性
max-age和expires設(shè)置過(guò)期時(shí)間
Secure只在https的時(shí)候發(fā)送
HttpOnly無(wú)法通過(guò)document.cookie訪問(wèn)
測(cè)試cookie返回的方式:
首先新建文件夾秽梅,然后新建server.js抹蚀、index.html。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>content</div>
</body>
<script>
console.log(document.cookie);
</script>
</html>
server.js
const http = require('http')
const fs = require('fs')
http.createServer(function (request, response) {
console.log('request come --- ', request.url)
if (request.url === '/') {
const html = fs.readFileSync('test.html', 'utf8')
response.writeHead(200, {
'Content-Type': 'text/html',
'Set-Cookie': 'id=123'
})
response.end(html)
}
}).listen('8888')
console.log('server listening on 8888')
1企垦、我們通過(guò)在請(qǐng)求頭中加入'Set-Cookie': 'id=123'环壤,來(lái)將Cookie寫(xiě)入到瀏覽器,隨后我們?cè)趇ndex.html中使用console.log(document.cookie);來(lái)打印當(dāng)前的cookie钞诡。
2郑现、我們也可以在chrome開(kāi)發(fā)者工具中的Application中可以查找到當(dāng)前的cookie
3、Cookie !== Session臭增,Cookie可以是Session的一種實(shí)現(xiàn)方式懂酱,但是Cookie和Session不是一一對(duì)應(yīng)的,Session有許多別的實(shí)現(xiàn)誊抛。
4列牺、cookie如果沒(méi)有設(shè)置過(guò)期時(shí)間,瀏覽器關(guān)閉拗窃,就過(guò)期了
5瞎领、chrome工具泌辫,hostAdmin,可以改host九默,域名映射震放。
6、同一個(gè)主域名下驼修,二級(jí)域名可以共享cookie
7殿遂、常用:使用cookie來(lái)保存session
8、只要是能定位到這個(gè)用戶(hù)乙各,就是一種session的實(shí)現(xiàn)方案
3.7HTTP長(zhǎng)連接
在HTTP/1.0中默認(rèn)使用短連接墨礁。也就是說(shuō),客戶(hù)端和服務(wù)器每進(jìn)行一次HTTP操作耳峦,就建立一次連接恩静,任務(wù)結(jié)束就中斷連接。當(dāng)客戶(hù)端瀏覽器訪問(wèn)的某個(gè)HTML或其他類(lèi)型的Web頁(yè)中包含有其他的Web資源(如JavaScript文件蹲坷、圖像文件驶乾、CSS文件等),每遇到這樣一個(gè)Web資源循签,瀏覽器就會(huì)重新建立一個(gè)HTTP會(huì)話级乐。
而從HTTP/1.1起,默認(rèn)使用長(zhǎng)連接懦底,用以保持連接特性唇牧。使用長(zhǎng)連接的HTTP協(xié)議罕扎,會(huì)在響應(yīng)頭加入這行代碼:
Connection:keep-alive
在使用長(zhǎng)連接的情況下聚唐,當(dāng)一個(gè)網(wǎng)頁(yè)打開(kāi)完成后,客戶(hù)端和服務(wù)器之間用于傳輸HTTP數(shù)據(jù)的TCP連接不會(huì)關(guān)閉腔召,客戶(hù)端再次訪問(wèn)這個(gè)服務(wù)器時(shí)杆查,會(huì)繼續(xù)使用這一條已經(jīng)建立的連接。Keep-Alive不會(huì)永久保持連接臀蛛,它有一個(gè)保持時(shí)間亲桦,可以在不同的服務(wù)器軟件(如Apache)中設(shè)定這個(gè)時(shí)間。實(shí)現(xiàn)長(zhǎng)連接需要客戶(hù)端和服務(wù)端都支持長(zhǎng)連接浊仆。
HTTP協(xié)議的長(zhǎng)連接和短連接客峭,實(shí)質(zhì)上是TCP協(xié)議的長(zhǎng)連接和短連接。
那么抡柿,長(zhǎng)連接的優(yōu)劣是什么舔琅?
由上可以看出,長(zhǎng)連接可以省去較多的TCP建立和關(guān)閉的操作洲劣,減少浪費(fèi)备蚓,節(jié)約時(shí)間课蔬。對(duì)于頻繁請(qǐng)求資源的客戶(hù)來(lái)說(shuō),較適用長(zhǎng)連接郊尝。不過(guò)這里存在一個(gè)問(wèn)題二跋,存活功能的探測(cè)周期太長(zhǎng),還有就是它只是探測(cè)TCP連接的存活流昏,屬于比較斯文的做法扎即,遇到惡意的連接時(shí),笨隽梗活功能就不夠使了铺遂。在長(zhǎng)連接的應(yīng)用場(chǎng)景下,client端一般不會(huì)主動(dòng)關(guān)閉它們之間的連接茎刚,Client與server之間的連接如果一直不關(guān)閉的話襟锐,會(huì)存在一個(gè)問(wèn)題,隨著客戶(hù)端連接越來(lái)越多膛锭,server早晚有扛不住的時(shí)候粮坞,這時(shí)候server端需要采取一些策略,如關(guān)閉一些長(zhǎng)時(shí)間沒(méi)有讀寫(xiě)事件發(fā)生的連接初狰,這樣可 以避免一些惡意連接導(dǎo)致server端服務(wù)受損莫杈;如果條件再允許就可以以客戶(hù)端機(jī)器為顆粒度,限制每個(gè)客戶(hù)端的最大長(zhǎng)連接數(shù)奢入,這樣可以完全避免某個(gè)蛋疼的客戶(hù)端連累后端服務(wù)筝闹。
短連接對(duì)于服務(wù)器來(lái)說(shuō)管理較為簡(jiǎn)單,存在的連接都是有用的連接腥光,不需要額外的控制手段关顷。但如果客戶(hù)請(qǐng)求頻繁,將在TCP的建立和關(guān)閉操作上浪費(fèi)時(shí)間和帶寬武福。
長(zhǎng)連接和短連接的產(chǎn)生在于client和server采取的關(guān)閉策略议双,具體的應(yīng)用場(chǎng)景采用具體的策略,沒(méi)有十全十美的選擇捉片,只有合適的選擇平痰。
接下來(lái)在node環(huán)境中測(cè)試下chrome長(zhǎng)連接的并發(fā)數(shù)限制
我們新建一個(gè)文件夾,里面新建三個(gè)文件伍纫,分別是:server.js宗雇、test.html、guo.jpg
test.html
const http = require('http')
const fs = require('fs')
http.createServer(function (request, response) {
console.log('request come --- ', request.url)
const html = fs.readFileSync('test.html', 'utf8')
const img = fs.readFileSync('guo.jpg')
if (request.url === '/') {
response.writeHead(200, {
'Content-Type': 'text/html',
// 默認(rèn)狀態(tài)keep-alive 創(chuàng)建一個(gè)tcp鏈接 可以并發(fā)多個(gè)http請(qǐng)求
// 'Connection': 'keep-alive',
// 關(guān)閉之后
// 'Connection': 'close'
})
response.end(html)
} else {
response.writeHead(200, {
'Content-Type': 'image/jpg',
'Connection': 'close'
})
response.end(img)
}
}).listen('8888')
console.log('server listening on 8888')
test.index.html
<body>
<!-- 用多張地址不一樣的圖片 -->
<div><img src="../guo.jpg" alt=""></div>
<div><img src="../guo2.jpg" alt=""></div>
<div><img src="../guo3.jpg" alt=""></div>
<div><img src="../guo4.jpg" alt=""></div>
<div><img src="../guo5.jpg" alt=""></div>
<div><img src="../guo6.jpg" alt=""></div>
<div><img src="../guo7.jpg" alt=""></div>
<div><img src="../guo8.jpg" alt=""></div>
<div><img src="../guo9.jpg" alt=""></div>
<div><img src="../guo10.jpg" alt=""></div>
<div><img src="../guo11.jpg" alt=""></div>
<div><img src="../guo12.jpg" alt=""></div>
<div><img src="../guo13.jpg" alt=""></div>
<div><img src="../guo14.jpg" alt=""></div>
<div><img src="../guo15.jpg" alt=""></div>
<div><img src="../guo16.jpg" alt=""></div>
</body>
打開(kāi)chrome的network可以發(fā)現(xiàn)莹规,由于并發(fā)數(shù)的限制赔蒲,最后一張圖片得等前面的幾個(gè)連接執(zhí)行完畢,才能加載,因此有了很長(zhǎng)的waterfull時(shí)間
3.8 數(shù)據(jù)協(xié)商
客戶(hù)端請(qǐng)求時(shí)會(huì)聲明希望拿到的數(shù)據(jù)格式和限制嘹履,服務(wù)端根據(jù)請(qǐng)求頭返回不同的數(shù)據(jù)
1. Accept
聲明想要的數(shù)據(jù)類(lèi)型腻扇,[主類(lèi)型]/[子類(lèi)型] ,如text/html砾嫉,image/jpg
2幼苛、Accept-Encoding
聲明進(jìn)行傳輸?shù)木幋a方式,主要是數(shù)據(jù)壓縮的算法焕刮,如gzip, deflate, br
3舶沿、Accept-Lanuage
聲明希望返回信息的語(yǔ)言,如zh-CN,zh;q=0.9(q表權(quán)重配并,0~1)
4括荡、User-Agent
聲明瀏覽器和操作系統(tǒng)的相關(guān)信息
2. Content
1、Content-Type
聲明返回的數(shù)據(jù)格式溉旋,如’X-Content-Type-Options’:‘nosniff’畸冲,可阻止瀏覽器自行猜測(cè)返回?cái)?shù)據(jù)類(lèi)型而引發(fā)的安全問(wèn)題。
不同的文件后綴對(duì)應(yīng)不同的Content-Type
2观腊、Content-Encoding
聲明返回的編碼方式邑闲,即數(shù)據(jù)壓縮
3、Content-Lanuage
聲明返回的語(yǔ)言
這里先實(shí)踐下在請(qǐng)求頭中聲明Content-Type和Content-Encoding梧油。
先上代碼苫耸,server.js:
const http = require('http')
const fs = require('fs')
const zlib = require('zlib')
http.createServer(function (request, response) {
console.log('request come', request.url)
const html = fs.readFileSync('index.html')
response.writeHead(200, {
'Content-Type': 'text/html',
'Content-Encoding': 'gzip' //聲明以gzip的方式傳輸
})
response.end(zlib.gzipSync(html))
// response.end(html)
}).listen('2333')
console.log('server listening on 2333')
上述代碼在請(qǐng)求頭重聲明了Content-Type和Content-Encoding,那么Content-Type我們肯定很好理解儡陨,他告訴了瀏覽器我們文本的格式是什么褪子。
接下來(lái)我們先看下在運(yùn)行node server.js啟動(dòng)之后,Network的截圖骗村。紅框中上面的數(shù)字是文件在傳輸過(guò)程中加上HTTP傳輸信息后的體積嫌褪,下面的數(shù)字則是body中內(nèi)容的體積。那么在Content-Type聲明gzip壓縮方式叙身,開(kāi)啟gzip壓縮后渔扎,傳輸時(shí)的體積會(huì)比body的體積更小,從而加快傳輸?shù)乃俣取?/p>
3.9redirect
重定向
通過(guò) url 訪問(wèn)某個(gè)路徑請(qǐng)求資源時(shí)信轿,發(fā)現(xiàn)資源不在 url 所指定的位置,這時(shí)服務(wù)器要告訴瀏覽器残吩,新的資源地址财忽,瀏覽器再重新請(qǐng)求新的 url,從而拿到資源泣侮。
若服務(wù)器指定了某個(gè)資源的地址即彪,現(xiàn)在需要更換地址,不應(yīng)該立刻廢棄掉 url,如果廢棄掉可能直接返回 404隶校,這時(shí)應(yīng)該告訴客戶(hù)端新的資源地址漏益。
node server.js啟動(dòng),發(fā)現(xiàn)url路徑自動(dòng)帶了/new深胳。
//server.js
const http = require('http')
const fs = require('fs')
http.createServer(function (request, response) {
console.log('request come', request.url)
if (request.url === '/') {
response.writeHead(302, {
'Location': '/new'
})
response.end()
} else if (request.url === '/new') {
response.writeHead(200, {
'Content-Type': 'text/html'
})
response.end(`<div>this is new Content</div>`)
}
}).listen('2333')
console.log('server listening on 2333')
可以看到根據(jù)定義的302臨時(shí)重定向绰疤,頁(yè)面自動(dòng)的加載到了/new路由下的內(nèi)容。
但如果我們需要永久重定向舞终,把status code 改成301即可轻庆。
Redirect 301 和 302 的區(qū)別
302 臨時(shí)跳轉(zhuǎn),每次請(qǐng)求仍然需要經(jīng)過(guò)服務(wù)端指定跳轉(zhuǎn)地址
301 永久跳轉(zhuǎn)
302的情況
每次訪問(wèn) locahost:8888敛劝,都要經(jīng)過(guò)服務(wù)端跳轉(zhuǎn)余爆,服務(wù)端通過(guò) console.log 可以看到 / → /new 兩次請(qǐng)求。
const http = require('http')
http.createServer(function (request, response) {
console.log('request come', request.url)
if (request.url === '/') {
response.writeHead(302, {
'Location': '/new'
})
response.end()
}
if (request.url === '/new') {
response.writeHead(200, {
'Content-Type': 'text/html',
})
response.end('<div>this is content</div>')
}
}).listen(8888)
console.log('server listening on 8888')
301 的情況
訪問(wèn) locahost:8888夸盟,第一次經(jīng)過(guò)服務(wù)端跳轉(zhuǎn)蛾方,服務(wù)端通過(guò) console.log 可以看到 / /new 兩次請(qǐng)求;第二次 服務(wù)端 console.log 只顯示 /new 上陕,沒(méi)有再次經(jīng)過(guò)服務(wù)器指定新的 Location转捕。
response.writeHead(301, {
'Location': '/new'
})
注意:使用 301 要慎重,一旦使用唆垃,服務(wù)端更改路由設(shè)置五芝,用戶(hù)如果不清理瀏覽器緩存,就會(huì)一直重定向辕万。
設(shè)置了 301枢步,locahost 會(huì)從緩存中讀取,并且這個(gè)緩存會(huì)保留到瀏覽器渐尿,當(dāng)我們?cè)L問(wèn) 8888 都會(huì)進(jìn)行跳轉(zhuǎn)醉途。此時(shí),就算服務(wù)端改變?cè)O(shè)置也是沒(méi)有用的砖茸,瀏覽器還是會(huì)從緩存中讀取隘擎。
3.10 內(nèi)容安全策略( CSP )
Content-Security-Policy 的作用:
使用白名單的方式告訴客戶(hù)端(瀏覽器)允許加載和不允許加載的資源。
向服務(wù)器舉報(bào)這種強(qiáng)貼牛皮鮮廣告的行為凉夯,以便做出更加針對(duì)性的措施予以絕殺货葬。
限制方式:
default-src 限制全局
指定資源類(lèi)型
connect-src、manifest-src劲够、img-src震桶、font-src/media-src、frame-src征绎、style-src蹲姐、script-src…
更詳細(xì)的文檔請(qǐng)移步MDN的:內(nèi)容安全策略( CSP )
- http/https 協(xié)議
1.0 協(xié)議缺陷:
無(wú)法復(fù)用鏈接,完成即斷開(kāi),重新慢啟動(dòng)和 TCP 3次握手
head of line blocking: 線頭阻塞柴墩,導(dǎo)致請(qǐng)求之間互相影響
1.1 改進(jìn):
長(zhǎng)連接(默認(rèn) keep-alive)忙厌,復(fù)用
host 字段指定對(duì)應(yīng)的虛擬站點(diǎn)
新增功能:
斷點(diǎn)續(xù)傳
身份認(rèn)證
狀態(tài)管理
cache 緩存
Cache-Control
Expires
Last-Modified
Etag
2.0:
多路復(fù)用
二進(jìn)制分幀層: 應(yīng)用層和傳輸層之間
首部壓縮
服務(wù)端推送
https: 較為安全的網(wǎng)絡(luò)傳輸協(xié)議
證書(shū)(公鑰)
SSL 加密
端口 443
TCP:
三次握手
四次揮手
滑動(dòng)窗口: 流量控制
擁塞處理
慢開(kāi)始
擁塞避免
快速重傳
快速恢復(fù)
緩存策略: 可分為 強(qiáng)緩存 和 協(xié)商緩存
Cache-Control/Expires: 瀏覽器判斷緩存是否過(guò)期,未過(guò)期時(shí)江咳,直接使用強(qiáng)緩存亦歉,Cache-Control的 max-age 優(yōu)先級(jí)高于 Expires
當(dāng)緩存已經(jīng)過(guò)期時(shí)颖御,使用協(xié)商緩存
唯一標(biāo)識(shí)方案: Etag(response 攜帶) & If-None-Match(request攜帶固歪,上一次返回的 Etag): 服務(wù)器判斷資源是否被修改上沐,
最后一次修改時(shí)間: Last-Modified(response) & If-Modified-Since (request,上一次返回的Last-Modified)
如果一致东臀,則直接返回 304 通知瀏覽器使用緩存
如不一致着饥,則服務(wù)端返回新的資源
Last-Modified 缺點(diǎn):
周期性修改,但內(nèi)容未變時(shí)惰赋,會(huì)導(dǎo)致緩存失效
最小粒度只到 s宰掉, s 以?xún)?nèi)的改動(dòng)無(wú)法檢測(cè)到
Etag 的優(yōu)先級(jí)高于 Last-Modified