IT即互聯網技術,從事的工做和網絡有很大的關係,前端要負責和後臺(服務器)進行交互,其必然得通過網絡,因此懂點網絡知識有很大的幫助。html
- Cache-Control 控制緩存行爲
- Connection 連接的管理
- Date 報文日期
- Pragma 報文指令
- Trailer 報文尾部的首部
- Trasfer-Encoding 指定報文主體的傳輸編碼方式
- Upgrade 升級爲其餘協議
- Via 代理服務器信息
- Warning 錯誤通知
複製代碼
- Accept 用戶代理可處理的媒體類型
- Accept-Charset 優先的字符集
- Accept-Encoding 優先的編碼
- Accept-Langulage 優先的語言
- Authorization Web 認證信息
- Expect 期待服務器的特定行爲
- From 用戶的電子郵箱地址
- Host 請求資源所在的服務器
- If-Match 比較實體標記
- If-Modified-Since 比較資源的更新時間,用於緩存
- If-None-Match 比較實體標記
- If-Range 資源未更新時發送實體Byte的範圍請求
- If-Unmodified-Since 比較資源的更新時間(和If-Modified-Since相反)
- Max-Forwards 最大傳輸跳數
- Proxy-Authorization 代理服務器須要客戶端認證
- Range 實體字節範圍請求
- Referer 請求中的URI的原始獲取方
- TE 傳輸編碼的優先級
- User-Agent HTTP 客戶端程序的信
複製代碼
const http = require('http'); http.createServer(function (req,res) { console.log(req.httpVersion)//打印請求行的協議版本號 console.log(req.url);//打印請求行的資源路徑 console.log(req.method)//打印請求行方法 console.log(req.headers);//打印求頭 //打印請求體,若是沒有請求體不會觸發data事件,通常用於POST、PUT等 req.on('data',function (data) { console.log(data) }); req.on('end',function (data) {//每次必定會觸發'end' console.log(data); }) }).listen(3000); 複製代碼
- Accept-Ranges 是否接受字節範圍,用於206範圍請求
- Age 資源的建立時間
- ETag 資源的匹配信息
- Location 客戶端重定向至指定的URI
- Proxy-Authenticate 代理服務器對客戶端的認證信息
- Retry-After 再次發送請求的時機
- Server 服務器的信息
- Vary 代理服務器緩存的管理信息
- www-Authenticate 服務器對客戶端的認證
複製代碼
- Allow 資源可支持的HTTP方法
- Content-Encoding 實體的編碼方式
- Content-Language 實體的天然語言
- Content-Length 實體的內容大小(字節爲單位)
- Content-Location 替代對應資源的URI
- Content-MD5 實體的報文摘要
- Content-Range 實體的位置範圍
- Content-Type 實體主體的媒體類型
- Expires 實體過時時間,用於緩存
- Last-Modified 資源的最後修改時間,用於緩存
複製代碼
//客戶端請求:curl -v --header 'Range:bytes=0-3' localhost:4000 //download.txt => 1234567890\r\n1234567890\r\n1234567890\r\n const http = require('http'); const fs = require('fs'); const size = fs.statSync('./download.txt').size; http.createServer(function (req,res) { let head = req.headers['range']; if(head){ let [,start,end] = head.match(/(\d*)-(\d*)/); start = start?Number(start):0; end = end ? Number(end) : size-1; console.log(start,end) res.statusCode = 206;//狀態碼爲206 res.setHeader('Accept-Ranges','bytes'); //服務器代表這是一個範圍請求,範圍請求的單位爲字節 res.setHeader('Content-Length',end-start+1);//響應體的字節 res.setHeader('Content-Range', `bytes ${start}-${end}/${size}`)//響應體在響應報文中的位置 fs.createReadStream('./download.txt',{start,end}).pipe(res); }else{ fs.createReadStream('./download.txt').pipe(res); } }).listen(4000); 複製代碼
// Referer表示這個資源被哪一個網站引用了 // 若是當前請求的referer和當前服務器的域名不同表示圖片被盜了 const http = require('http'); const url = require('url'); const path = require('path'); const fs = require('fs'); const {promisify} = require('util'); const stat = promisify(fs.stat); let whiteList = ['localhost'] http.createServer(async function (req, res) { let { pathname } = url.parse(req.url); let realPath = path.join(__dirname, 'static', pathname); let s = await stat(realPath); if(s.isDirectory()){ fs.createReadStream(path.join(realPath, '/index.html')).pipe(res); }else{ let refer = req.headers['referer'] || req.headers['referred']; if (refer){ // 當前引用的資源有沒有refer let host = req.headers.host.split(':')[0]; let r = url.parse(req.headers['referer']).hostname; if (whiteList.includes(r) || r === host ){ //當前的請求網頁host和主機名refer相同說明有訪問權限 fs.createReadStream(realPath).pipe(res); }else{ // 沒有權限就返回裂圖 fs.createReadStream(path.join(__dirname,'static/1.jpg')).pipe(res); } }else{ fs.createReadStream(realPath).pipe(res); } } }).listen(5000); 複製代碼
//客戶端請求頭:Accept-Language: en,zh;q=0.8,ja;q=0.9 const messages = { en: 'hello world', ja: 'こんにちは、世界', zh: '你好世界', } let defaultEncoding = 'zh' const http = require('http'); let server = http.createServer(function (req,res) { let lan = req.headers['accept-language']; if (lan){ //en,zh;q=0.8,ja;q=0.9 => [en, zh;q=0.8 ,ja;q=0.9] //而且按照權重排序 let lans = lan.split(',').map(l=>{ let q = l.split(';')[1] ? Number(l.split(';')[1].split('=')[1]):1; return { name: l.split(';')[0],q } }).sort((a,b)=>b.q-a.q); let l = null for (let key in lans){ if (messages[lans[key].name]){ l = messages[lans[key].name]; break; } } console.log(l); if(l){ res.setHeader('Content-Type', 'text/html;charset=utf8;') res.end(l); }else{ res.setHeader('Content-Type', 'text/html;charset=utf8;') res.end(messages[defaultEncoding]); } }else{ res.setHeader('Content-Type','text/html;charset=utf8;') res.end(messages[defaultEncoding]) } }).listen(5000); 複製代碼
強制緩存+最後修改時間對比緩存:前端
const http = require('http'); const path = require('path'); const fs = require('fs'); const url = require('url'); const {promisify} = require('util'); const mime = require('mime'); const stat = promisify(fs.stat); const static = path.join(__dirname,'static') http.createServer(async function (req,res) { let {pathname} = url.parse(req.url,true); if(pathname === '/favicon.ico') return res.end(); let realPath = path.join(static,pathname); let statObj = await stat(realPath);//請求的資源信息 //強制請求 res.setHeader('Cache-Control','no-cache'); // 10s內不會再次發起請求 let time = req.headers['if-modified-since'];// 瀏覽器再次到來時 會帶上一個頭 if-modified-since的字段 if(statObj.isFile()){ //對比緩存,把當前文件的最後修改時間發送告訴給客戶端 res.setHeader('Last-Modified', statObj.ctime.toGMTString()); res.setHeader('Content-Type',mime.getType(realPath)+';chatset=utf8'); if (time === statObj.ctime.toGMTString()) { // 若是相等那就走緩存吧 res.statusCode = 304; res.end(); }else{ fs.createReadStream(realPath).pipe(res); } } }).listen(3000); // 最後修改時間 通常會有些偏差 時間可能不會那麼精確(一秒內改了屢次) // CDN 分發的時間不一樣 可能也會致使緩存失效 複製代碼
強制緩存+關鍵字對比緩存:node
const http = require('http'); const path = require('path'); const fs = require('fs'); const url = require('url'); const {promisify} = require('util'); const mime = require('mime'); const stat = promisify(fs.stat); const crypto = require('crypto'); cosnt static = path.join(__dirname,'static'); http.createServer(async function (req,res) { let {pathname} = url.parse(req.url,true); if(pathname === '/favicon.ico') return res.end(); let realPath = path.join(static,pathname); let statObj = await stat(realPath); //強制緩存 res.setHeader('Cache-Control','no-cache'); // 10s內不會再次發起請求 if(statObj.isFile()){ //對比緩存:Etag內容爲請求資源通過MD5加密以後 let rs = fs.createReadStream(realPath); let md5 = crypto.createHash('md5'); rs.on('data',function (data) { md5.update(data); }); rs.on('end',function () { let r = md5.digest('base64'); res.setHeader('Etag',r ); if (req.headers['if-none-match'] === r ){ res.statusCode = 304; res.end(); }else{ res.setHeader('Content-Type', mime.getType(realPath) + ';chatset=utf8'); fs.createReadStream(realPath).pipe(res); } }) } }).listen(3000); // 若是文件很是大,須要讀取文件的內容比對,影響性能 複製代碼
//獲取瀏覽器支持的壓縮方式Accept-Encoding: gzip, deflate, br //壓縮而且通知瀏覽器使用的壓縮方式Content-Encoding: gzip const http = require('http'); const fs = require('fs'); const zlib = require('zlib'); http.createServer(function (req,res) { let encoding = req.headers['accept-encoding']; if(encoding){ if (encoding.match(/\bgzip\b/)){ res.setHeader('Content-Encoding','gzip'); fs.createReadStream('./static/index.html').pipe(zlib.createGzip()).pipe(res); } else if (encoding.match(/\bdeflate\b/)){ res.setHeader('Content-Encoding', 'deflate'); fs.createReadStream('./static/index.html').pipe(zlib.createDeflate()).pipe(res); }else{ fs.createReadStream('./static/index.html').pipe(res); } }else{ fs.createReadStream('./static/index.html').pipe(res); } }).listen(3000); 複製代碼
// const http = require('http'); const server = http.createServer(function (req,res) { if(req.url === '/visit'){ if(req.headers['cookie']){ res.setHeader('Content-Type', 'text/html;charset=utf-8'); let queryObj=require('querystring').parse(req.headers['cookie'); queryObj.visit++; res.setHeader('Set-Cookie', `visit=${queryObj.visit}; httpOnly`); res.end('你是第' + queryObj.visit+ '次訪問') }else{ res.setHeader('Content-Type','text/html;charset=utf8'); res.setHeader('Set-Cookie','visit=1; httpOnly'); res.end('你是第一次訪問') } } }).listen(6000); 複製代碼
const http = require('http'); const uuid = require('uuid/v4'); const SESSION_ID = 'connet.sid'; // 卡號:110 = {m:1000} cosnt session = {} // csrf 加驗證碼 refer let server = http.createServer(function (req, res) { if (req.url === '/go') { let cookies = require('querystring').parse(req.headers['cookie'],'; ','='); if (cookies[SESSION_ID] && session[cookies[SESSION_ID]]) { session[cookies[SESSION_ID]].m -= 200; res.setHeader('Content-Type', 'text/html;charset=utf8'); res.end('你的卡有' + session[cookies[SESSION_ID]].m + '元'); } else { let cardId = uuid(); session[cardId] = { m: 1000 }; res.setHeader('Set-Cookie', `${SESSION_ID}=${cardId}`); res.setHeader('Content-Type', 'text/html;charset=utf8'); console.log(session) res.end('你的卡有' + session[cardId].m + '元'); } } }).listen(8888); 複製代碼
// www.self1.cn 代理 localhost:3001 // www.self2.cn 代理 localhost:3002 const map = { 'www.self1.cn': 'http://localhost:3001', 'www.self2.cn': 'http://localhost:3002', } const httpProxy = require('http-proxy'); const http = require('http'); const proxy = httpProxy.createProxyServer(); http.createServer(function (req, res) { let head = req.headers['host']; proxy.web(req, res, { target: map[head] }); }).listen(80); 複製代碼
const http = require('http') http.createServer(function (req, res) { res.header("Access-Control-Allow-Origin", "*");//容許的域名( * 全部域) res.header("Access-Control-Allow-Headers", "X-Requested-With");/服務器支持的頭信息 res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");//容許的方法 }).listen(9000, function () { console.log('server is runing at 9000') }) 複製代碼
IT即互聯網技術,從事的工做和網絡有很大的關係,前端要負責和後臺(服務器)進行交互,其必然得通過網絡,因此懂點網絡知識有很大的幫助。接下來會介紹:web
本文參考:跨域