成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

HTTP面試指南

FreeZinG / 1923人閱讀

摘要:報(bào)文主體并不是一定要有的。緩存緩存作用減少了冗余的數(shù)據(jù)傳輸,節(jié)省了網(wǎng)費(fèi)。當(dāng)資源發(fā)生改變時(shí),也隨之發(fā)生變化。本人水平有限,有不足之處,望大家指出改正。

前言

或許你在面試時(shí)遇到過這樣的問題:從輸入U(xiǎn)RL到瀏覽器顯示頁面發(fā)生了什么?
簡單的回答就是:

DNS解析

TCP建立連接

發(fā)送HTTP請(qǐng)求

服務(wù)器處理請(qǐng)求

如果有緩存直接讀緩存

沒有緩存返回響應(yīng)內(nèi)容

TCP斷開連接

瀏覽器解析渲染頁面

如果你覺得這樣回答過于簡單,不如來深入了解一下吧。

網(wǎng)絡(luò)基礎(chǔ)

在此之前,先了解一下TCP/IP基礎(chǔ)知識(shí)。

TCP/IP參考模型

早期的TCP/IP模型是一個(gè)四層結(jié)構(gòu),從下往上依次是網(wǎng)絡(luò)接口層、互聯(lián)網(wǎng)層、傳輸層和應(yīng)用層,后來將網(wǎng)絡(luò)接口層劃分為了物理層和數(shù)據(jù)鏈路層

應(yīng)用層(Application)提供網(wǎng)絡(luò)與用戶應(yīng)用軟件之間的接口服務(wù)

傳輸層(Transimission)提供建立、維護(hù)和取消傳輸連接功能,負(fù)責(zé)可靠地傳輸數(shù)據(jù)(PC)
傳輸層有兩個(gè)性質(zhì)不同的協(xié)議:TCP(傳輸控制協(xié)議)和UDP(用戶數(shù)據(jù)報(bào)協(xié)議)

網(wǎng)絡(luò)層(Network)處理網(wǎng)絡(luò)間路由,確保數(shù)據(jù)及時(shí)傳送(路由器)

數(shù)據(jù)鏈路層(DataLink)負(fù)責(zé)無錯(cuò)傳輸數(shù)據(jù),確認(rèn)幀、發(fā)錯(cuò)重傳等(交換機(jī))

物理層(Physics)提供機(jī)械、電氣、功能和過程特性(網(wǎng)卡、網(wǎng)線、雙絞線、同軸電纜、中繼器)

各層常用協(xié)議

這里可以看到HTTP協(xié)議是構(gòu)建于TCP之上,屬于應(yīng)用層協(xié)議。

具體過程 1. DNS解析

DNS服務(wù)是和HTTP協(xié)議一樣位于應(yīng)用層的協(xié)議,提供域名到IP地址的解析服務(wù)。

得到IP地址后就可以建立連接了,這里還有兩個(gè)知識(shí)需要了解:

持久連接

持久連接(也稱為HTTP keep-alive)的特點(diǎn)是,只要任意一段沒有提出斷開連接,就保持TCP連接狀態(tài)。

管線化

持久連接建立后就可以使用管線化發(fā)送了,可以同時(shí)并發(fā)多個(gè)請(qǐng)求,不用等待一個(gè)接一個(gè)的響應(yīng)。(在這里我想到了流的pipe方法。)

2. TCP連接與斷開 2.1 TCP報(bào)文格式


大致說一下:

計(jì)算機(jī)通過端口號(hào)識(shí)別訪問哪個(gè)服務(wù),比如http;源端口號(hào)進(jìn)行隨機(jī)端口,目的端口決定哪個(gè)程序進(jìn)行接收

數(shù)據(jù)序號(hào)和確認(rèn)序號(hào)用于保障傳輸數(shù)據(jù)的完整性和順序

需要注意的是TCP的連接、傳輸和斷開都受六個(gè)控制位的指揮(比如三次握手和四次揮手)

PSH(push急迫位)緩存區(qū)將滿,立刻速度傳輸

RST(reset重置位)連接斷了重新連接

URG(urgent緊急位)緊急信號(hào)

ACK(acknowlegement確認(rèn))為1就表示確認(rèn)號(hào)

SYN(synchronous建立聯(lián)機(jī))同步序號(hào)位 TCP建立連接時(shí)將這個(gè)值設(shè)為1

用戶數(shù)據(jù)存儲(chǔ)了應(yīng)用層生成的HTTP報(bào)文

了解了這些,那么開始講重點(diǎn)

2.2 TCP三次握手和四次揮手

三次握手

客戶端先發(fā)送一個(gè)帶SYN標(biāo)志的數(shù)據(jù)包給服務(wù)器端

服務(wù)器收到后,回傳一個(gè)帶有SYN/ACK標(biāo)志的數(shù)據(jù)包表示確認(rèn)收到

客戶端再發(fā)送一個(gè)帶SYN/ACK標(biāo)志的數(shù)據(jù)包,代表握手結(jié)束

四次揮手

客戶端向服務(wù)器發(fā)出了FIN報(bào)文段

服務(wù)器收到后,回復(fù)一個(gè)ACK應(yīng)答

服務(wù)器也向客戶端發(fā)送一個(gè)FIN報(bào)文段,隨后關(guān)閉了服務(wù)器端的連接

客戶端收到之后,又向服務(wù)器回復(fù)一個(gè)ACK應(yīng)答,過了一段計(jì)時(shí)等待,客戶端也關(guān)閉了連接(計(jì)時(shí)等待是為了確認(rèn)服務(wù)器端已正常關(guān)閉)

四次揮手并不是必然的,當(dāng)服務(wù)器已經(jīng)沒有內(nèi)容發(fā)給客戶端了,就直接發(fā)送FIN報(bào)文段,這樣就變成了三次揮手。
3. HTTP請(qǐng)求/響應(yīng) 3.1 HTTP報(bào)文

HTTP報(bào)文大致可分為報(bào)文首部和報(bào)文主體兩塊,兩者由空行(就相當(dāng)于用了兩個(gè)換行符rnrn)來劃分。報(bào)文主體并不是一定要有的。

3.1.1 請(qǐng)求報(bào)文

常用請(qǐng)求行方法:

GET 獲取資源

POST 向服務(wù)器端發(fā)送數(shù)據(jù),傳輸實(shí)體主體

PUT 傳輸文件

HEAD 獲取報(bào)文首部

DELETE 刪除文件

OPTIONS 詢問支持的方法

TRACE 追蹤路徑

3.1.2 響應(yīng)報(bào)文

說到響應(yīng)報(bào)文,就必要談到狀態(tài)碼:

2XX 成功

200(OK) 客戶端發(fā)過來的數(shù)據(jù)被正常處理

204(Not Content) 正常響應(yīng),沒有實(shí)體

206(Partial Content) 范圍請(qǐng)求,返回部分?jǐn)?shù)據(jù),響應(yīng)報(bào)文中由Content-Range指定實(shí)體內(nèi)容

3XX 重定向

301(Moved Permanently) 永久重定向

302(Found) 臨時(shí)重定向,規(guī)范要求方法名不變,但是都會(huì)改變

303(See Other) 和302類似,但必須用GET方法

304(Not Modified) 狀態(tài)未改變 配合(If-Match、If-Modified-Since、If-None_Match、If-Range、If-Unmodified-Since) (通常緩存會(huì)返回304狀態(tài)碼)

4XX 客戶端錯(cuò)誤

400(Bad Request) 請(qǐng)求報(bào)文語法錯(cuò)誤

401 (unauthorized) 需要認(rèn)證

403(Forbidden) 服務(wù)器拒絕訪問對(duì)應(yīng)的資源

404(Not Found) 服務(wù)器上無法找到資源

5XX 服務(wù)器端錯(cuò)誤

500(Internal Server Error) 服務(wù)器故障

503(Service Unavailable) 服務(wù)器處于超負(fù)載或正在停機(jī)維護(hù)

3.1.3 首部

通用首部

首部字段名 說明
Cache-Control 控制緩存行為
Connection 連接的管理
Date 報(bào)文日期
Pragma 報(bào)文指令
Trailer 報(bào)文尾部的首部
Trasfer-Encoding 指定報(bào)文主體的傳輸編碼方式
Upgrade 升級(jí)為其他協(xié)議
Via 代理服務(wù)器信息
Warning 錯(cuò)誤通知

請(qǐng)求首部

首部字段名 說明
Accept 用戶代理可處理的媒體類型
Accept-Charset 優(yōu)先的字符集
Accept-Encoding 優(yōu)先的編碼
Accept-Langulage 優(yōu)先的語言
Authorization Web認(rèn)證信息
Expect 期待服務(wù)器的特定行為
From 用戶的電子郵箱地址
Host 請(qǐng)求資源所在的服務(wù)器
If-Match 比較實(shí)體標(biāo)記
If-Modified-Since 比較資源的更新時(shí)間
If-None-Match 比較實(shí)體標(biāo)記
If-Range 資源未更新時(shí)發(fā)送實(shí)體Byte的范圍請(qǐng)求
If-Unmodified-Since 比較資源的更新時(shí)間(和If-Modified-Since相反)
Max-Forwards 最大傳輸條數(shù)
Proxy-Authorization 代理服務(wù)器需要客戶端認(rèn)證
Range 實(shí)體字節(jié)范圍請(qǐng)求
Referer 請(qǐng)求中的URI的原始獲取方
TE 傳輸編碼的優(yōu)先級(jí)
User-Agent HTTP客戶端程序的信息

響應(yīng)首部

首部字段名 說明
Accept-Ranges 是否接受字節(jié)范圍
Age 資源的創(chuàng)建時(shí)間
ETag 資源的匹配信息
Location 客戶端重定向至指定的URI
Proxy-Authenticate 代理服務(wù)器對(duì)客戶端的認(rèn)證信息
Retry-After 再次發(fā)送請(qǐng)求的時(shí)機(jī)
Server 服務(wù)器的信息
Vary 代理服務(wù)器緩存的管理信息
www-Authenticate 服務(wù)器對(duì)客戶端的認(rèn)證

實(shí)體首部

首部字段名 說明
Allow 資源可支持的HTTP方法
Content-Encoding 實(shí)體的編碼方式
Content-Language 實(shí)體的自然語言
Content-Length 實(shí)體的內(nèi)容大小(字節(jié)為單位)
Content-Location 替代對(duì)應(yīng)資源的URI
Content-MD5 實(shí)體的報(bào)文摘要
Content-Range 實(shí)體的位置范圍
Content-Type 實(shí)體主體的媒體類型
Expires 實(shí)體過期時(shí)間
Last-Modified 資源的最后修改時(shí)間
3.2 實(shí)現(xiàn)客戶端訪問服務(wù)端

創(chuàng)建HTTP服務(wù)端

let http = require("http");
let app = http.createServer((req, res) => {// req是可讀流/res是可寫流
    // 獲取請(qǐng)求報(bào)文信息
    let method = req.method;// 方法
    let httpVersion = req.httpVersion;// HTTP版本
    let url = req.url;
    let headers = req.headers;
    console.log(method, httpVersion, url, headers);
    // 獲取請(qǐng)求體(如果請(qǐng)求體的數(shù)據(jù)大于64k,data事件會(huì)被觸發(fā)多次)
    let buffers = [];
    req.on("data", data => {
        buffers.push(data);
    })
    req.on("end", () => {
        console.log(Buffer.concat(buffers).toString());
        res.write("hello");
        res.end("world");
    })
})
// 監(jiān)聽服務(wù)器事件
app.on("connection", socket => {
    console.log("建立連接");
});
app.on("close", () => {
    console.log("服務(wù)器關(guān)閉")
});
app.on("error", err => {
    console.log(err);
});
app.listen(3000, () => {
    console.log("server is starting on port 3000");
});

創(chuàng)建客戶端

let http = require("http");
let options = {
    hostname: "localhost",
    port: 3000,
    path: "/",
    method: "GET",
    // 設(shè)置實(shí)體首部 告訴服務(wù)端我當(dāng)前要給你發(fā)什么樣的數(shù)據(jù)
    headers: {
        "content-Type": "application/x-www-form-urlencoded",
        "Content-Length": 15
    }
}
let req = http.request(options);
req.on("response", res => {
    res.on("data", chunk => {
        console.log(chunk.toString());
    });
});
req.end("name=js&&age=22")

然后使用node運(yùn)行我們的客戶端

說了這么多,你可能已經(jīng)大致了解了
從輸入U(xiǎn)RL到瀏覽器顯示頁面發(fā)生了什么,不用多說,我們?cè)賮砜匆幌?strong>緩存。

4. 緩存 4.1 緩存作用

減少了冗余的數(shù)據(jù)傳輸,節(jié)省了網(wǎng)費(fèi)。

減少了服務(wù)器的負(fù)擔(dān), 大大提高了網(wǎng)站的性能

加快了客戶端加載網(wǎng)頁的速度

4.2 緩存分類
強(qiáng)制緩存

強(qiáng)制緩存:說白了就是第一次請(qǐng)求數(shù)據(jù)時(shí),服務(wù)端將數(shù)據(jù)和緩存規(guī)則一并返回,下一次請(qǐng)求時(shí)瀏覽器直接根據(jù)緩存規(guī)則進(jìn)行判斷,有就直接讀緩存數(shù)據(jù)庫,不用連接服務(wù)器;沒有,再去找服務(wù)器。

對(duì)比緩存

對(duì)比緩存,顧名思義,需要進(jìn)行比較判斷是否可以使用緩存。

瀏覽器第一次請(qǐng)求數(shù)據(jù)時(shí),服務(wù)器會(huì)將緩存標(biāo)識(shí)與數(shù)據(jù)一起返回給客戶端,客戶端將二者備份至緩存數(shù)據(jù)庫中。

再次請(qǐng)求數(shù)據(jù)時(shí),客戶端將備份的緩存標(biāo)識(shí)發(fā)送給服務(wù)器,服務(wù)器根據(jù)緩存標(biāo)識(shí)進(jìn)行判斷,判斷成功后,返回304狀態(tài)碼,通知* 客戶端比較成功,可以使用緩存數(shù)據(jù)。

4.3 請(qǐng)求流程
第一次請(qǐng)求,此時(shí)沒有緩存

第二次請(qǐng)求

從上張圖我們可以看到,判斷緩存是否可用,有兩種方式

ETag是實(shí)體標(biāo)簽的縮寫,根據(jù)實(shí)體內(nèi)容生成的一段hash字符串,可以標(biāo)識(shí)資源的狀態(tài)。當(dāng)資源發(fā)生改變時(shí),ETag也隨之發(fā)生變化。ETag是Web服務(wù)端產(chǎn)生的,然后發(fā)給瀏覽器客戶端。

Last-Modified是此資源的最后修改時(shí)間,

如果客戶端在請(qǐng)求到的資源中發(fā)現(xiàn)實(shí)體首部里有Last-Modified聲明,再次請(qǐng)求就會(huì)在頭里帶上if-Modified-Since字段

服務(wù)端收到請(qǐng)求后發(fā)現(xiàn)if-Modified-Since字段則與被請(qǐng)求資源的最后修改時(shí)間進(jìn)行對(duì)比

說了這么多,不如直接來實(shí)現(xiàn)一下緩存

通過最后修改時(shí)間來判斷緩存是否可用

let http = require("http");
let url = require("url");
let path = require("path");
let fs = require("fs");
let mime = require("mime");
let app = http.createServer((req, res) => {
    // 根據(jù)url獲取客戶端要請(qǐng)求的文件路徑
    let { parsename } = url.parse(req.url);
    let p = path.join(__dirname, "public", "." + pathname);
    // fs.stat()用來讀取文件信息,文件最后修改時(shí)間就是stat.ctime
    fs.stat(p, (err, stat) => {
        if (!err) {
            let since = req.headers["if-modified-since"];//客戶端發(fā)來的文件最后修改時(shí)間
            if (since) {
                if (since === stat.ctime.toUTCString()) {//最后修改時(shí)間相等,讀緩存
                    res.statusCode = 304;
                    res.end();
                } else {
                    sendFile(req, res, p, stat);//最后修改時(shí)間不相等,返回新內(nèi)容
                }
            } else {
                sendError(res);
            }
        }
    })
})
function sendError(res) {
    res.statusCode = 404;
    res.end();
}
function sendFile(req, res, p, stat) {
    res.setHeader("Cache-Control", "no-cache");// 設(shè)置通用首部字段 控制緩存行為
    res.setHeader("Last-Modified", stat.ctime.toUTCString());// 實(shí)體首部字段 資源最后修改時(shí)間
    res.setHeader("Content-Type", mime.getType(p) + ";charset=utf8")
    fs.createReadStream(p).pipe(res);
}
app.listen(3000, () => {
    console.log("server is starting on port 3000");
});
最后修改時(shí)間存在問題:
1. 某些服務(wù)器不能精確得到文件的最后修改時(shí)間, 這樣就無法通過最后修改時(shí)間來判斷文件是否更新了。
2. 某些文件的修改非常頻繁,在秒以下的時(shí)間內(nèi)進(jìn)行修改. Last-Modified只能精確到秒。
3. 一些文件的最后修改時(shí)間改變了,但是內(nèi)容并未改變。 我們不希望客戶端認(rèn)為這個(gè)文件修改了。
4. 如果同樣的一個(gè)文件位于多個(gè)CDN服務(wù)器上的時(shí)候內(nèi)容雖然一樣,修改時(shí)間不一樣。

通過ETag來判斷緩存是否可用

ETag就是根據(jù)文件內(nèi)容來判斷,說白了就是采用MD5(md5并不叫加密算法,它不可逆,應(yīng)該叫摘要算法)產(chǎn)生信息摘要,用摘要來進(jìn)行比對(duì)。

let http = require("http");
let url = require("url");
let path = require("path");
let fs = require("fs");
let mime = require("mime");
// crypto是node.js中實(shí)現(xiàn)加密和解密的模塊 具體詳解請(qǐng)自行了解
let crypto = require("crypto");
let app = http.createServer((req, res) => {
    // 根據(jù)url獲取客戶端要請(qǐng)求的文件路徑
    let { parsename } = url.parse(req.url);
    let p = path.join(__dirname, "public", "." + pathname);
    // fs.stat()用來讀取文件信息,文件最后修改時(shí)間就是stat.ctime
    fs.stat(p, (err, stat) => {
        let md5 = crypto.createHash("md5");//創(chuàng)建md5對(duì)象
        let rs = fs.createReadStream(p);
        rs.on("data", function (data) {
            md5.update(data);
        });
        rs.on("end", () => {
            let r = md5.digest("hex"); // 對(duì)文件進(jìn)行md5加密
            // 下次就拿最新文件的加密值 和客戶端請(qǐng)求來比較
            let ifNoneMatch = req.headers["if-none-match"];
            if (ifNoneMatch) {
                if (ifNoneMatch === r) {
                    res.statusCode = 304;
                    res.end();
                } else {
                    sendFile(req, res, p, r);
                }
            } else {
                sendFile(req, res, p, r);
            }
        });
    })
});
function sendError(res) {
    res.statusCode = 404;
    res.end();
}
function sendFile(req, res, p, stat) {
    res.setHeader("Cache-Control", "no-cache");// 設(shè)置通用首部字段 控制緩存行為
    res.setHeader("Etag", r);// 響應(yīng)首部字段 資源的匹配信息
    res.setHeader("Content-Type", mime.getType(p) + ";charset=utf8")
    fs.createReadStream(p).pipe(res);
}
app.listen(3000, () => {
    console.log("server is starting on port 3000");
});
最后

想深入學(xué)習(xí)http的同學(xué),我推薦一本書《圖解HTTP》。
本人水平有限,有不足之處,望大家指出改正。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/94579.html

相關(guān)文章

  • 前端開發(fā)應(yīng)屆生面試指南(含各大公司具體指南面試真題)

    摘要:先介紹一下本人應(yīng)屆前端開發(fā)一枚,非科班出身,專業(yè)是化學(xué),大學(xué)期間開始自學(xué)前端開發(fā),在今年春招實(shí)習(xí)和秋招的時(shí)候投了一些公司,拿到一些京東拼多多虎牙等,總體來說還算滿意,特地寫一篇文章來總結(jié)一下面試的那些套路。 showImg(https://segmentfault.com/img/remote/1460000011897700); 先介紹一下本人應(yīng)屆前端開發(fā)一枚,非科班出身,專業(yè)是化學(xué)...

    sunnyxd 評(píng)論0 收藏0
  • 前端開發(fā)應(yīng)屆生面試指南(含各大公司具體指南面試真題)

    摘要:先介紹一下本人應(yīng)屆前端開發(fā)一枚,非科班出身,專業(yè)是化學(xué),大學(xué)期間開始自學(xué)前端開發(fā),在今年春招實(shí)習(xí)和秋招的時(shí)候投了一些公司,拿到一些京東拼多多虎牙等,總體來說還算滿意,特地寫一篇文章來總結(jié)一下面試的那些套路。 showImg(https://segmentfault.com/img/remote/1460000011897700); 先介紹一下本人應(yīng)屆前端開發(fā)一枚,非科班出身,專業(yè)是化學(xué)...

    jeyhan 評(píng)論0 收藏0
  • 前端開發(fā)應(yīng)屆生面試指南(含各大公司具體指南面試真題)

    摘要:先介紹一下本人應(yīng)屆前端開發(fā)一枚,非科班出身,專業(yè)是化學(xué),大學(xué)期間開始自學(xué)前端開發(fā),在今年春招實(shí)習(xí)和秋招的時(shí)候投了一些公司,拿到一些京東拼多多虎牙等,總體來說還算滿意,特地寫一篇文章來總結(jié)一下面試的那些套路。 showImg(https://segmentfault.com/img/remote/1460000011897700); 先介紹一下本人應(yīng)屆前端開發(fā)一枚,非科班出身,專業(yè)是化學(xué)...

    lentoo 評(píng)論0 收藏0
  • PHPer面試指南-Web 篇

    摘要:擴(kuò)展閱讀收集的前端面試題和答案前端開發(fā)面試題史上最全的前端面試題匯總及答案前端工程師手冊(cè)協(xié)議工作原理協(xié)議運(yùn)行機(jī)制的概述 本書的 GitHub 地址:https://github.com/todayqq/PH... 對(duì)于大公司,很少會(huì)有全棧工程師這個(gè)崗位,全棧是個(gè)花哨的詞,對(duì)于現(xiàn)在比較熱門的技術(shù),不論是 Vue 還是 Laravel,只要智商不差,看著文檔,都能寫出一個(gè) CURD 來,...

    cnio 評(píng)論0 收藏0
  • PHPer 面試指南-擴(kuò)展閱讀資源整理

    摘要:前端篇收集的前端面試題和答案前端開發(fā)面試題史上最全的前端面試題匯總及答案前端工程師手冊(cè)協(xié)議工作原理協(xié)議運(yùn)行機(jī)制的概述協(xié)議篇原理原理解析的工作原理與的區(qū)別理解后端篇年的面試總結(jié)垃圾回收機(jī)制面向?qū)ο笤O(shè)計(jì)淺談?wù)f清楚是什么和的區(qū)別索引原理及慢查 前端篇 收集的前端面試題和答案 前端開發(fā)面試題 史上最全的web前端面試題匯總及答案 前端工程師手冊(cè) HTTP協(xié)議:工作原理 SSL/TLS協(xié)議運(yùn)行...

    wemall 評(píng)論0 收藏0
  • PHPer面試指南-協(xié)議篇

    摘要:地址每次面試多多少少都會(huì)被問到等等之類協(xié)議,協(xié)議相關(guān)的問題也可以說是面試必備,所以我把這些知識(shí)單獨(dú)收集成了一篇文章。即標(biāo)志位和標(biāo)志位均為。發(fā)送完畢后,服務(wù)器端進(jìn)入狀態(tài)。認(rèn)證服務(wù)器對(duì)客戶端進(jìn)行認(rèn)證以后,確認(rèn)無誤,同意發(fā)放令牌。 Git 地址:https://github.com/todayqq/PH... 每次面試多多少少都會(huì)被問到 HTTP、HTTPS、TCP、Socket、 OAu...

    megatron 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<