兩者區別:瀏覽器對http響應頭會進行特定處理(如自動讀取本地緩存、設置cookie等),而http客戶端(如crul)可能沒有像瀏覽器那樣的處理,某些封裝程度高的http客戶端,可能會有。
同一個文件夾中有三個文件:
使用了http標准庫的js客戶端:
const http = require('http'); const options = { hostname: '127.0.0.1', port: 8080, path: '/api', method: 'GET' }; const req = http.request(options, function (res) { console.log('STATUS:' + res.statusCode); console.log('HEADERS:' + JSON.stringify(res.headers)); res.setEncoding('utf-8'); let data = ""; res.on('data', function (chunk) { console.log(`接收到數據:${chunk}\r\n`); data += chunk; }); res.on('end', function () { console.log('響應結束'); console.log('接收到的數據為:' + data); }); }); req.end();
用於瀏覽器發起請求的h5頁面:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="msg"></div> <script> var xhr = new XMLHttpRequest(); xhr.open("GET","http://127.0.0.1:8080/api",true); xhr.send(null); xhr.onload = function(){ document.querySelector("#msg").innerHTML = xhr.responseText; } </script> </body> </html>
js服務端:
const http = require("http"); const fs = require("fs"); const server = http.createServer(function(req,res){ res.setHeader('Content-Type','text/html;charset=utf-8'); switch(true){ case req.url.startsWith('/index'): fs.readFile('./index.html',"utf-8",function (_,data) { res.end(data); }); break; case req.url.startsWith('/api'): console.log(JSON.stringify(req.headers)); res.end("每次請求都返回一個隨機數:" + Math.random()); break; } }); server.listen(8080,'127.0.0.1',function(){ console.log(`服務器運行在8080`); });
后續測試環境為:
訪問地址:http://127.0.0.1:8080/index
以上地址每次訪問,都會顯示不同的隨機數。
測試強緩存
服務器返回數據前,加上個強緩存設置(10s):
case req.url.startsWith('/api'): console.log(JSON.stringify(req.headers)); let curTime = +new Date(); let cacheOutDateTime = curTime + 10*1000; let GMTTime = new Date(cacheOutDateTime).toGMTString(); res.setHeader('Expires', GMTTime); res.end("每次請求都返回一個隨機數:" + Math.random()); break;
瀏覽器訪問地址:http://localhost:8080/index
10s內不停刷新瀏覽器,顯示的隨機數都是一樣的,說明強緩存生效了。
通過js客戶端來訪問,強緩存無效:
C:\Users\MRLWJ\Desktop\知識分享10-25\web\srv>node client.js STATUS:200 HEADERS:{"content-type":"text/html;charset=utf-8","expires":"Wed, 24 Oct 2018 15:58:26 GMT","date":"Wed, 24 Oct 2018 15:58:16 GMT","connection":"close","content-length":"59"} 接收到數據:每次請求都返回一個隨機數:0.005061696884948619 響應結束 接收到的數據為:每次請求都返回一個隨機數:0.005061696884948619 C:\Users\MRLWJ\Desktop\知識分享10-25\web\srv>node client.js STATUS:200 HEADERS:{"content-type":"text/html;charset=utf-8","expires":"Wed, 24 Oct 2018 15:58:27 GMT","date":"Wed, 24 Oct 2018 15:58:17 GMT","connection":"close","content-length":"57"} 接收到數據:每次請求都返回一個隨機數:0.9111832960061363 響應結束 接收到的數據為:每次請求都返回一個隨機數:0.9111832960061363
通過postman客戶端來訪問也是一樣,強緩存無效。
結論:強緩存的頭(這里測試的是expires)只能作用在瀏覽器上,對於這里的http客戶端無效,因為這里的http客戶端根本就沒有用到那個http頭,更別說還會自己去設置本地緩存了,這些工作瀏覽器才會去做。
測試協商緩存
添加一個etag頭:
case req.url.startsWith('/api'): console.log(JSON.stringify(req.headers)); res.setHeader('Etag', '123'); res.end("每次請求都返回一個隨機數:" + Math.random()); break;
多次訪問頁面,瀏覽器自動帶上了if-none-match頭
但是協商緩存沒有生效,以上兩個數值明明一樣的。原因在於if-none-match對應的數值,僅僅是給服務端用於校驗而已,如果服務端沒有讀取這個值進行校驗的話,則什么效果都沒有。要有效果的話,則要求服務端校驗完成后,返回個302狀態碼,才能使瀏覽器使用本地緩存。
if-none-match:代表本地已經有緩存了,而且這個緩存的標識符是123。服務器知道這些信息之后,再用於判斷是否需要告訴瀏覽器去使用緩存(是否要返回304)。
假如直接返回304的話,則訪問/api時,雖然能完成請求(打開chrome調試工具,顯示響應狀態碼為304),但響應數據為空:
case '/api': console.log(JSON.stringify(req.headers)); res.statusCode = 304; res.end("每次請求都返回一個隨機數:" + Math.random()); break;
正確的判斷方式,以下設置了304之后,不管有沒有返回正文內容,正文內容都會被忽略
case req.url.startsWith('/api'): console.log(JSON.stringify(req.headers)); res.setHeader('Etag', "123"); if("123" == req.headers['if-none-match']){ res.statusCode = 304; res.end(); } res.end("每次請求都返回一個隨機數:" + Math.random()); break; } });
修改完成后,用瀏覽器多次請求,都使用的是本地緩存,即顯示到界面上的隨機數一直無變化。
然后再用js客戶端進行請求,結果如下:
C:\Users\MRLWJ\Desktop\知識分享10-25\web\srv>node client.js STATUS:200 HEADERS:{"content-type":"text/html;charset=utf-8","etag":"123","date":"Wed, 24 Oct 2018 16:25:53 GMT","connection":"close","content-length":"57"} 接收到數據:每次請求都返回一個隨機數:0.7875283103348185 響應結束 接收到的數據為:每次請求都返回一個隨機數:0.7875283103348185 C:\Users\MRLWJ\Desktop\知識分享10-25\web\srv>node client.js STATUS:200 HEADERS:{"content-type":"text/html;charset=utf-8","etag":"123","date":"Wed, 24 Oct 2018 16:25:54 GMT","connection":"close","content-length":"57"} 接收到數據:每次請求都返回一個隨機數:0.2601388266595912 響應結束 接收到的數據為:每次請求都返回一個隨機數:0.2601388266595912
結論: 因為這個http客戶端沒有像瀏覽器那樣遵守了http規范,接收到etag時,下次請求時沒有帶上if-none-match,導致服務器沒辦法用於判斷,所以一直返回200,導致協商緩存失效。