一個合格的中級前端工程師需要掌握的技能筆記(中)
Github來源:一個合格的中級前端工程師需要掌握的技能 | 求星星 ? | 給個??關(guān)注,??點(diǎn)贊,??鼓勵一下作者
大家好,我是魔王哪吒,很高興認(rèn)識你~~
哪吒人生信條:如果你所學(xué)的東西 處于喜歡 才會有強(qiáng)大的動力支撐。
每天學(xué)習(xí)編程,讓你離夢想更新一步,感謝不負(fù)每一份熱愛編程的程序員,不論知識點(diǎn)多么奇葩,和我一起,讓那一顆四處流蕩的心定下來,一直走下去,加油,2021加油!歡迎關(guān)注加我vx:xiaoda0423,歡迎點(diǎn)贊、收藏和評論
不要害怕做夢,但是呢,也不要光做夢,要做一個實(shí)干家,而不是空談家,求真力行。
前言
如果這篇文章有幫助到你,給個??關(guān)注,??點(diǎn)贊,??鼓勵一下作者,接收好挑戰(zhàn)了嗎?文章公眾號首發(fā),關(guān)注 程序員哆啦A夢 第一時間獲取最新的文章
JavaScript模塊
性能
在原型鏈上查找屬性比較耗時,對性能有副作用,這在性能要求苛刻的情況下很重要。另外,試圖訪問不存在的屬性時會遍歷整個原型鏈。
遍歷對象的屬性時,原型鏈上的每個可枚舉屬性都會被枚舉出來。要檢查對象是否具有自己定義的屬性,而不是其原型鏈上的某個屬性,則必須使用所有對象從 Object.prototype 繼承的 hasOwnProperty
JavaScript中的相等性判斷
抽象(非嚴(yán)格)相等比較 ( ==)嚴(yán)格相等比較 ( ===): 用于Array.prototype.indexOf,Array.prototype.lastIndexOf, 和case-matching同值零: 用于 %TypedArray%和ArrayBuffer構(gòu)造函數(shù)、以及Map和Set操作, 并將用于ES2016/ES7中的String.prototype.includes同值: 用于所有其他地方
嚴(yán)格相等
===
var num = 0;
var obj = new String("0");
var str = "0";
var b = false;
console.log(num === num); // true
console.log(obj === obj); // true
console.log(str === str); // true
console.log(num === obj); // false
console.log(num === str); // false
console.log(obj === str); // false
console.log(null === undefined); // false
console.log(obj === null); // false
console.log(obj === undefined); // false
非嚴(yán)格相等 ==
var num = 0;
var obj = new String("0");
var str = "0";
var b = false;
console.log(num == num); // true
console.log(obj == obj); // true
console.log(str == str); // true
console.log(num == obj); // true
console.log(num == str); // true
console.log(obj == str); // true
console.log(null == undefined); // true
// both false, except in rare cases
console.log(obj == null);
console.log(obj == undefined);
并發(fā)模型與事件循環(huán)
JavaScript有一個基于事件循環(huán)的并發(fā)模型,事件循環(huán)負(fù)責(zé)執(zhí)行代碼、收集和處理事件以及執(zhí)行隊列中的子任務(wù)。這個模型與其它語言中的模型截然不同,比如 C 和 Java。
運(yùn)行時概念-可視化描述

堆
對象被分配在堆中,堆是一個用來表示一大塊內(nèi)存區(qū)域的計算機(jī)術(shù)語。
隊列
一個 JavaScript 運(yùn)行時包含了一個待處理消息的消息隊列。每一個消息都關(guān)聯(lián)著一個用以處理這個消息的回調(diào)函數(shù)。
函數(shù)的處理會一直進(jìn)行到執(zhí)行棧再次為空為止;然后事件循環(huán)將會處理隊列中的下一個消息(如果還有的話)。
內(nèi)存管理
JavaScript是在創(chuàng)建變量(對象,字符串等)時自動進(jìn)行了分配內(nèi)存,并且在不使用它們時“自動”釋放。釋放的過程稱為垃圾回收。
內(nèi)存生命周期
分配你所需要的內(nèi)存 使用分配到的內(nèi)存(讀、寫) 不需要時將其釋放\歸還
JavaScript 的內(nèi)存分配
示例:
var n = 123; // 給數(shù)值變量分配內(nèi)存
var s = "azerty"; // 給字符串分配內(nèi)存
var o = {
a: 1,
b: null
}; // 給對象及其包含的值分配內(nèi)存
// 給數(shù)組及其包含的值分配內(nèi)存(就像對象一樣)
var a = [1, null, "abra"];
function f(a){
return a + 2;
} // 給函數(shù)(可調(diào)用的對象)分配內(nèi)存
// 函數(shù)表達(dá)式也能分配一個對象
someElement.addEventListener('click', function(){
someElement.style.backgroundColor = 'blue';
}, false);
var d = new Date(); // 分配一個 Date 對象
var e = document.createElement('div'); // 分配一個 DOM 元素
var s = "azerty";
var s2 = s.substr(0, 3); // s2 是一個新的字符串
// 因?yàn)樽址遣蛔兞浚?br>// JavaScript 可能決定不分配內(nèi)存,
// 只是存儲了 [0-3] 的范圍。
var a = ["ouais ouais", "nan nan"];
var a2 = ["generation", "nan nan"];
var a3 = a.concat(a2);
// 新數(shù)組有四個元素,是 a 連接 a2 的結(jié)果
垃圾回收:
引用計數(shù)垃圾收集 標(biāo)記-清除算法
對象原型
理解對象的原型(可以通過Object.getPrototypeOf(obj)或者已被棄用的__proto__屬性獲得)與構(gòu)造函數(shù)的prototype屬性之間的區(qū)別是很重要的。前者是每個實(shí)例上都有的屬性,后者是構(gòu)造函數(shù)的屬性。也就是說,Object.getPrototypeOf(new Foobar())和Foobar.prototype指向著同一個對象。

Object.prototype.valueOf()valueOf() 方法返回指定對象的原始值。
語法
object.valueOf()
返回值
返回值為該對象的原始值。
示例:
// Array:返回數(shù)組對象本身
var array = ["ABC", true, 12, -5];
console.log(array.valueOf() === array); // true
// Date:當(dāng)前時間距1970年1月1日午夜的毫秒數(shù)
var date = new Date(2013, 7, 18, 23, 11, 59, 230);
console.log(date.valueOf()); // 1376838719230
// Number:返回數(shù)字值
var num = 15.26540;
console.log(num.valueOf()); // 15.2654
// 布爾:返回布爾值true或false
var bool = true;
console.log(bool.valueOf() === bool); // true
// new一個Boolean對象
var newBool = new Boolean(true);
// valueOf()返回的是true,兩者的值相等
console.log(newBool.valueOf() == newBool); // true
// 但是不全等,兩者類型不相等,前者是boolean類型,后者是object類型
console.log(newBool.valueOf() === newBool); // false
// Object:返回對象本身
var obj = {name: "張三", age: 18};
console.log( obj.valueOf() === obj ); // true
Object.is()
Object.is() 方法判斷兩個值是否為同一個值。
語法
Object.is(value1, value2);
示例:
Object.is('foo', 'foo'); // true
Object.is(window, window); // true
Object.is('foo', 'bar'); // false
Object.is([], []); // false
var foo = { a: 1 };
var bar = { a: 1 };
Object.is(foo, foo); // true
Object.is(foo, bar); // false
Object.is(null, null); // true
// 特例
Object.is(0, -0); // false
Object.is(0, +0); // true
Object.is(-0, -0); // true
Object.is(NaN, 0/0); // true
函數(shù)
在 JavaScript中,函數(shù)是頭等(first-class)對象,因?yàn)樗鼈兛梢韵袢魏纹渌麑ο笠粯泳哂袑傩院头椒ā?/p>
IIFE是在函數(shù)聲明后立即調(diào)用的函數(shù)表達(dá)式。
函數(shù)生成器聲明 (
function*語句)
function* name([param[, param[, ...param]]]) { statements }
函數(shù)生成器表達(dá)式 (
function*表達(dá)式)
function* [name]([param] [, param] [..., param]) { statements }
JavaScript 數(shù)據(jù)類型和數(shù)據(jù)結(jié)構(gòu)
最新的 ECMAScript 標(biāo)準(zhǔn)定義了 8 種數(shù)據(jù)類型:
6 種原始類型,使用 typeof 運(yùn)算符檢查:
undefined:typeof instance === "undefined"
Boolean:typeof instance === "boolean"
Number:typeof instance === "number"
String:typeof instance === "string
BigInt:typeof instance === "bigint"
Symbol :typeof instance === "symbol"
null:typeof instance === "object"。
Object:typeof instance === "object"。
JavaScript 中的類型包括:
Number(數(shù)字)
String(字符串)
Boolean(布爾)
Function(函數(shù))
Object(對象)
Symbol(ES2015 新增)
JavaScript 中的類型應(yīng)該包括這些:
Number(數(shù)字)
String(字符串)
Boolean(布爾)
Symbol(符號)(ES2015 新增)
Object(對象)
Function(函數(shù))
Array(數(shù)組)
Date(日期)
RegExp(正則表達(dá)式)
null(空)
undefined(未定義)
表達(dá)式和運(yùn)算符
function*
function* 關(guān)鍵字定義了一個 generator 函數(shù)表達(dá)式。
yield
暫停和恢復(fù) generator 函數(shù)。
yield*
委派給另外一個generator函數(shù)或可迭代的對象。
值屬性
Infinity
NaN
undefined
globalThis
Function 屬性
eval()
isFinite()
isNaN()
parseFloat()
parseInt()
decodeURI()
decodeURIComponent()
encodeURI()
encodeURIComponent()
基本對象
Object
Function
Boolean
Symbol
錯誤對象
Error
AggregateError
EvalError
InternalError
RangeError
ReferenceError
SyntaxError
TypeError
URIError
Numbers & dates
Number
BigInt
Math
Date
文本處理
String RegExp
索引集合類
Array
Int8Array
Uint8Array
Uint8ClampedArray
Int16Array
Uint16Array
Int32Array
Uint32Array
Float32Array
Float64Array
BigInt64Array
BigUint64Array
Keyed collections
Map
Set
WeakMap
WeakSet
WeakMap
WeakMap 對象是一組鍵/值對的集合,其中的鍵是弱引用的。其鍵必須是對象,而值可以是任意的。
WeakSet
WeakSet 對象允許你將弱保持對象存儲在一個集合中。
結(jié)構(gòu)化數(shù)據(jù)
ArrayBuffer
SharedArrayBuffer
Atomics
DataView
JSON
控制抽象化
Promise
Generator
GeneratorFunction
AsyncFunction
反射
Reflect
Proxy
Generator
生成器對象是由一個 generator function 返回的,并且它符合可迭代協(xié)議和迭代器協(xié)議。
語法
function* gen() {
yield 1;
yield 2;
yield 3;
}
let g = gen();
// "Generator { }"
方法
Generator.prototype.next()
返回一個由 yield表達(dá)式生成的值。
Generator.prototype.return()
返回給定的值并結(jié)束生成器。
Generator.prototype.throw()
向生成器拋出一個錯誤。
一個無限迭代器
function* idMaker(){
let index = 0;
while(true)
yield index++;
}
let gen = idMaker(); // "Generator { }"
console.log(gen.next().value);
// 0
console.log(gen.next().value);
// 1
console.log(gen.next().value);
// 2
// ...
Generator.prototype.next()
next() 方法返回一個包含屬性 done 和 value 的對象。該方法也可以通過接受一個參數(shù)用以向生成器傳值。
語法
gen.next(value)
使用 next()方法
function* gen() {
yield 1;
yield 2;
yield 3;
}
var g = gen(); // "Generator { }"
g.next(); // "Object { value: 1, done: false }"
g.next(); // "Object { value: 2, done: false }"
g.next(); // "Object { value: 3, done: false }"
g.next(); // "Object { value: undefined, done: true }"
向生成器傳值
第一次調(diào)用沒有記錄任何內(nèi)容,因?yàn)樯善髯畛鯖]有產(chǎn)生任何結(jié)果。
function* gen() {
while(true) {
var value = yield null;
console.log(value);
}
}
var g = gen();
g.next(1);
// "{ value: null, done: false }"
g.next(2);
// 2
// "{ value: null, done: false }"
Proxy
Proxy 對象用于創(chuàng)建一個對象的代理,從而實(shí)現(xiàn)基本操作的攔截和自定義
語法
const p = new Proxy(target, handler)
const handler = {
get: function(obj, prop) {
return prop in obj ? obj[prop] : 37;
}
};
const p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;
console.log(p.a, p.b); // 1, undefined
console.log('c' in p, p.c); // false, 37




構(gòu)造函數(shù)-實(shí)例-原型之間的關(guān)系

作用域

普通類型的存儲方式

引用類型的存儲方式

函數(shù)柯里化是一個為多參函數(shù)實(shí)現(xiàn)遞歸降解
示例:

map方法


filter方法

reduce方法

every方法

some方法

find方法

數(shù)組扁平化
利用ES6語法flat(num)方法將數(shù)組拉平。使用遞歸...。
HTTP模塊
HTTP是一種能夠獲取如 HTML 這樣的網(wǎng)絡(luò)資源的 protocol(通訊協(xié)議)。它是在 Web 上進(jìn)行數(shù)據(jù)交換的基礎(chǔ),是一種 client-server 協(xié)議,也就是說,請求通常是由像瀏覽器這樣的接受方發(fā)起的。一個完整的Web文檔通常是由不同的子文檔拼接而成的,像是文本、布局描述、圖片、視頻、腳本等等。

客戶端和服務(wù)端通過交換各自的消息(與數(shù)據(jù)流正好相反)進(jìn)行交互。由像瀏覽器這樣的客戶端發(fā)出的消息叫做 requests,被服務(wù)端響應(yīng)的消息叫做 responses。

HTTP是一種可擴(kuò)展的協(xié)議。它是應(yīng)用層的協(xié)議,通過TCP,或者是TLS-加密的TCP連接來發(fā)送,理論上任何可靠的傳輸協(xié)議都可以使用。
基于
HTTP的組件系統(tǒng)
HTTP是一個client-server協(xié)議:請求通過一個實(shí)體被發(fā)出,實(shí)體也就是用戶代理。大多數(shù)情況下,這個用戶代理都是指瀏覽器,當(dāng)然它也可能是任何東西,比如一個爬取網(wǎng)頁生成維護(hù)搜索引擎索引的機(jī)器爬蟲。
每一個發(fā)送到服務(wù)器的請求,都會被服務(wù)器處理并返回一個消息,也就是response。在這個請求與響應(yīng)之間,還有許許多多的被稱為proxies的實(shí)體,他們的作用與表現(xiàn)各不相同,比如有些是網(wǎng)關(guān),還有些是caches等。
實(shí)際上,在一個瀏覽器和處理請求的服務(wù)器之間,還有路由器、調(diào)制解調(diào)器等許多計算機(jī)。由于Web的層次設(shè)計,那些在網(wǎng)絡(luò)層和傳輸層的細(xì)節(jié)都被隱藏起來了。HTTP位于最上層的應(yīng)用層。雖然底層對于分析網(wǎng)絡(luò)問題非常重要,但是大多都跟對HTTP的描述不相干。
客戶端:
user-agent
user-agent 就是任何能夠?yàn)橛脩舭l(fā)起行為的工具。這個角色通常都是由瀏覽器來扮演。一些例外情況,比如是工程師使用的程序,以及Web開發(fā)人員調(diào)試應(yīng)用程序。
瀏覽器總是作為發(fā)起一個請求的實(shí)體,他永遠(yuǎn)不是服務(wù)器(雖然近幾年已經(jīng)出現(xiàn)一些機(jī)制能夠模擬由服務(wù)器發(fā)起的請求消息了)。
要展現(xiàn)一個網(wǎng)頁,瀏覽器首先發(fā)送一個請求來獲取頁面的HTML文檔,再解析文檔中的資源信息發(fā)送其他請求,獲取可執(zhí)行腳本或CSS樣式來進(jìn)行頁面布局渲染,以及一些其它頁面資源(如圖片和視頻等)。然后,瀏覽器將這些資源整合到一起,展現(xiàn)出一個完整的文檔,也就是網(wǎng)頁。瀏覽器執(zhí)行的腳本可以在之后的階段獲取更多資源,并相應(yīng)地更新網(wǎng)頁。
一個網(wǎng)頁就是一個超文本文檔。也就是說,有一部分顯示的文本可能是鏈接,啟動它(通常是鼠標(biāo)的點(diǎn)擊)就可以獲取一個新的網(wǎng)頁,使得用戶可以控制客戶端進(jìn)行網(wǎng)上沖浪。瀏覽器來負(fù)責(zé)發(fā)送HTTP請求,并進(jìn)一步解析HTTP返回的消息,以向用戶提供明確的響應(yīng)。
Web服務(wù)端
在上述通信過程的另一端,是由Web Server來服務(wù)并提供客戶端所請求的文檔。Server只是虛擬意義上代表一個機(jī)器:它可以是共享負(fù)載(負(fù)載均衡)的一組服務(wù)器組成的計算機(jī)集群,也可以是一種復(fù)雜的軟件,通過向其他計算機(jī)(如緩存,數(shù)據(jù)庫服務(wù)器,電子商務(wù)服務(wù)器 ...)發(fā)起請求來獲取部分或全部資源。
Server 不一定是一臺機(jī)器,但一個機(jī)器上可以裝載的眾多Servers。在HTTP/1.1 和Host頭部中,它們甚至可以共享同一個IP地址。
代理(Proxies)
在瀏覽器和服務(wù)器之間,有許多計算機(jī)和其他設(shè)備轉(zhuǎn)發(fā)了HTTP消息。由于Web棧層次結(jié)構(gòu)的原因,它們大多都出現(xiàn)在傳輸層、網(wǎng)絡(luò)層和物理層上,對于HTTP應(yīng)用層而言就是透明的,雖然它們可能會對應(yīng)用層性能有重要影響。還有一部分是表現(xiàn)在應(yīng)用層上的,被稱為代理(Proxies)。代理(Proxies)既可以表現(xiàn)得透明,又可以不透明(“改變請求”會通過它們)。代理主要有如下幾種作用:
緩存(可以是公開的也可以是私有的,像瀏覽器的緩存) 過濾(像反病毒掃描,家長控制...) 負(fù)載均衡(讓多個服務(wù)器服務(wù)不同的請求) 認(rèn)證(對不同資源進(jìn)行權(quán)限管理) 日志記錄(允許存儲歷史信息)
HTTP的基本性質(zhì)
HTTP 是簡單的
雖然下一代HTTP/2協(xié)議將HTTP消息封裝到了幀(frames)中,HTTP大體上還是被設(shè)計得簡單易讀。HTTP報文能夠被人讀懂,還允許簡單測試,降低了門檻,對新人很友好。
HTTP 是可擴(kuò)展的
在 HTTP/1.0 中出現(xiàn)的 HTTP headers 讓協(xié)議擴(kuò)展變得非常容易。只要服務(wù)端和客戶端就新 headers 達(dá)成語義一致,新功能就可以被輕松加入進(jìn)來。
HTTP 是無狀態(tài),有會話的
HTTP是無狀態(tài)的:在同一個連接中,兩個執(zhí)行成功的請求之間是沒有關(guān)系的。這就帶來了一個問題,用戶沒有辦法在同一個網(wǎng)站中進(jìn)行連續(xù)的交互,比如在一個電商網(wǎng)站里,用戶把某個商品加入到購物車,切換一個頁面后再次添加了商品,這兩次添加商品的請求之間沒有關(guān)聯(lián),瀏覽器無法知道用戶最終選擇了哪些商品。而使用HTTP的頭部擴(kuò)展,HTTP Cookies就可以解決這個問題。把Cookies添加到頭部中,創(chuàng)建一個會話讓每次請求都能共享相同的上下文信息,達(dá)成相同的狀態(tài)。
注意,HTTP本質(zhì)是無狀態(tài)的,使用Cookies可以創(chuàng)建有狀態(tài)的會話。

HTTP和連接
一個連接是由傳輸層來控制的,這從根本上不屬于HTTP的范圍。HTTP并不需要其底層的傳輸層協(xié)議是面向連接的,只需要它是可靠的,或不丟失消息的(至少返回錯誤)。在互聯(lián)網(wǎng)中,有兩個最常用的傳輸層協(xié)議:TCP是可靠的,而UDP不是。因此,HTTP依賴于面向連接的TCP進(jìn)行消息傳遞,但連接并不是必須的。
在客戶端(通常指瀏覽器)與服務(wù)器能夠交互(客戶端發(fā)起請求,服務(wù)器返回響應(yīng))之前,必須在這兩者間建立一個 TCP 鏈接,打開一個 TCP 連接需要多次往返交換消息(因此耗時)。HTTP/1.0 默認(rèn)為每一對 HTTP 請求/響應(yīng)都打開一個單獨(dú)的 TCP 連接。當(dāng)需要連續(xù)發(fā)起多個請求時,這種模式比多個請求共享同一個 TCP 鏈接更低效。
為了減輕這些缺陷,HTTP/1.1引入了流水線(被證明難以實(shí)現(xiàn))和持久連接的概念:底層的TCP連接可以通過Connection頭部來被部分控制。HTTP/2則發(fā)展得更遠(yuǎn),通過在一個連接復(fù)用消息的方式來讓這個連接始終保持為暖連接。
為了更好的適合HTTP,設(shè)計一種更好傳輸協(xié)議的進(jìn)程一直在進(jìn)行。Google就研發(fā)了一種以UDP為基礎(chǔ),能提供更可靠更高效的傳輸協(xié)議QUIC
HTTP 能控制什么
可以被HTTP控制的常見特性:
緩存
文檔如何緩存能通過HTTP來控制。服務(wù)端能告訴代理和客戶端哪些文檔需要被緩存,緩存多久,而客戶端也能夠命令中間的緩存代理來忽略存儲的文檔。
開放同源限制
為了防止網(wǎng)絡(luò)窺聽和其它隱私泄漏,瀏覽器強(qiáng)制對Web網(wǎng)站做了分割限制。只有來自于相同來源的網(wǎng)頁才能夠獲取網(wǎng)站的全部信息。這樣的限制有時反而成了負(fù)擔(dān),HTTP可以通過修改頭部來開放這樣的限制,因此Web文檔可以是由不同域下的信息拼接成的(某些情況下,這樣做還有安全因素考慮)。
認(rèn)證
一些頁面能夠被保護(hù)起來,僅讓特定的用戶進(jìn)行訪問。基本的認(rèn)證功能可以直接通過HTTP提供,使用Authenticate相似的頭部即可,或用HTTP Cookies來設(shè)置指定的會話。
代理和隧道
通常情況下,服務(wù)器和/或客戶端是處于內(nèi)網(wǎng)的,對外網(wǎng)隱藏真實(shí) IP 地址。因此 HTTP 請求就要通過代理越過這個網(wǎng)絡(luò)屏障。但并非所有的代理都是 HTTP 代理。例如,SOCKS協(xié)議的代理就運(yùn)作在更底層,一些像 FTP 這樣的協(xié)議也能夠被它們處理。
會話
使用HTTP Cookies允許你用一個服務(wù)端的狀態(tài)發(fā)起請求,這就創(chuàng)建了會話。雖然基本的HTTP是無狀態(tài)協(xié)議。這很有用,不僅是因?yàn)檫@能應(yīng)用到像購物車這樣的電商業(yè)務(wù)上,更是因?yàn)檫@使得任何網(wǎng)站都能輕松為用戶定制展示內(nèi)容了。
HTTP流
當(dāng)客戶端想要和服務(wù)端進(jìn)行信息交互時(服務(wù)端是指最終服務(wù)器,或者是一個中間代理),過程表現(xiàn)為下面幾步:
打開一個TCP連接:TCP連接被用來發(fā)送一條或多條請求,以及接受響應(yīng)消息。客戶端可能打開一條新的連接,或重用一個已經(jīng)存在的連接,或者也可能開幾個新的TCP連接連向服務(wù)端。 發(fā)送一個HTTP報文:HTTP報文(在HTTP/2之前)是語義可讀的。在HTTP/2中,這些簡單的消息被封裝在了幀中,這使得報文不能被直接讀取,但是原理仍是相同的。
GET / HTTP/1.1
Host: xxx.org
Accept-Language: fr
讀取服務(wù)端返回的報文信息:
HTTP/1.1 200 OK
Date: Sat, 09 Oct xxx 14:28:02 GMT
Server: Apache
Last-Modified: Tue, 01 Dec 2009 20:18:22 GMT
ETag: "xxx-7449-xxx"
Accept-Ranges: bytes
Content-Length: 29769
Content-Type: text/html
<!DOCTYPE html... (here comes the 29769 bytes of the requested web page)
關(guān)閉連接或者為后續(xù)請求重用連接。
當(dāng)HTTP流水線啟動時,后續(xù)請求都可以不用等待第一個請求的成功響應(yīng)就被發(fā)送。然而HTTP流水線已被證明很難在現(xiàn)有的網(wǎng)絡(luò)中實(shí)現(xiàn),因?yàn)楝F(xiàn)有網(wǎng)絡(luò)中有很多老舊的軟件與現(xiàn)代版本的軟件共存。因此,HTTP流水線已被在有多請求下表現(xiàn)得更穩(wěn)健的HTTP/2的幀所取代。
HTTP報文
HTTP/1.1以及更早的HTTP協(xié)議報文都是語義可讀的。在HTTP/2中,這些報文被嵌入到了一個新的二進(jìn)制結(jié)構(gòu),幀。幀允許實(shí)現(xiàn)很多優(yōu)化,比如報文頭部的壓縮和復(fù)用。即使只有原始HTTP報文的一部分以HTTP/2發(fā)送出來,每條報文的語義依舊不變,客戶端會重組原始HTTP/1.1請求。因此用HTTP/1.1格式來理解HTTP/2報文仍舊有效。
有兩種HTTP報文的類型,請求與響應(yīng),每種都有其特定的格式。
請求 HTTP請求的一個例子:

請求由以下元素組成:
一個 HTTP的method,經(jīng)常是由一個動詞像GET, POST或者一個名詞像OPTIONS,HEAD來定義客戶端的動作行為。通常客戶端的操作都是獲取資源(GET方法)或者發(fā)送HTML form表單值(POST方法),雖然在一些情況下也會有其他操作。要獲取的資源的路徑,通常是上下文中就很明顯的元素資源的 URL,它沒有protocol(http://),domain(xxxx.xxx.org),或是TCP的port(en-US)(HTTP一般在80端口)。HTTP協(xié)議版本號。為服務(wù)端表達(dá)其他信息的可選頭部 headers。對于一些像 POST這樣的方法,報文的body就包含了發(fā)送的資源,這與響應(yīng)報文的body類似。
響應(yīng) HTTP響應(yīng)的一個例子:

響應(yīng)報文包含了下面的元素:
HTTP協(xié)議版本號。 一個狀態(tài)碼( status code),來告知對應(yīng)請求執(zhí)行成功或失敗,以及失敗的原因。一個狀態(tài)信息,這個信息是非權(quán)威的狀態(tài)碼描述信息,可以由服務(wù)端自行設(shè)定。 HTTP headers,與請求頭部類似。可選項,比起請求報文,響應(yīng)報文中更常見地包含獲取的資源 body。
基于
HTTP的APIs
基于HTTP的最常用API是XMLHttpRequest API,可用于在user agent和服務(wù)器之間交換數(shù)據(jù)。現(xiàn)代Fetch API提供相同的功能,具有更強(qiáng)大和靈活的功能集。
另一種API,即服務(wù)器發(fā)送的事件,是一種單向服務(wù),允許服務(wù)器使用HTTP作為傳輸機(jī)制向客戶端發(fā)送事件。使用EventSource接口,客戶端打開連接并建立事件句柄。客戶端瀏覽器自動將到達(dá)HTTP流的消息轉(zhuǎn)換為適當(dāng)?shù)?code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">Event對象,并將它們傳遞給專門處理這類type事件的句柄,如果有這么個句柄的話。但如果相應(yīng)的事件處理句柄根本沒有建立,那就交給onmessage (en-US)事件處理程序處理。
HTTP是一種簡單可擴(kuò)展的協(xié)議,其Client-Server的結(jié)構(gòu)以及輕松擴(kuò)展頭部信息的能力使得HTTP可以和Web共同發(fā)展。
即使HTTP/2為了提高性能將HTTP報文嵌入到幀中這一舉措增加了復(fù)雜度,但是從Web應(yīng)用的角度看,報文的基本結(jié)構(gòu)沒有變化,從HTTP/1.0發(fā)布起就是這樣的結(jié)構(gòu)。會話流依舊簡單,通過一個簡單的 HTTP message monitor就可以查看和糾錯。
HTTP緩存
通過復(fù)用以前獲取的資源,可以顯著提高網(wǎng)站和應(yīng)用程序的性能。Web 緩存減少了等待時間和網(wǎng)絡(luò)流量,因此減少了顯示資源表示形式所需的時間。通過使用 HTTP緩存,變得更加響應(yīng)性。
不同種類的緩存
緩存是一種保存資源副本并在下次請求時直接使用該副本的技術(shù)。當(dāng) web 緩存發(fā)現(xiàn)請求的資源已經(jīng)被存儲,它會攔截請求,返回該資源的拷貝,而不會去源服務(wù)器重新下載。這樣帶來的好處有:緩解服務(wù)器端壓力,提升性能(獲取資源的耗時更短了)。對于網(wǎng)站來說,緩存是達(dá)到高性能的重要組成部分。緩存需要合理配置,因?yàn)椴⒉皇撬匈Y源都是永久不變的:重要的是對一個資源的緩存應(yīng)截止到其下一次發(fā)生改變(即不能緩存過期的資源)。
緩存的種類有很多,其大致可歸為兩類:私有與共享緩存。共享緩存存儲的響應(yīng)能夠被多個用戶使用。私有緩存只能用于單獨(dú)用戶。本文將主要介紹瀏覽器與代理緩存,除此之外還有網(wǎng)關(guān)緩存、CDN、反向代理緩存和負(fù)載均衡器等部署在服務(wù)器上的緩存方式,為站點(diǎn)和 web 應(yīng)用提供更好的穩(wěn)定性、性能和擴(kuò)展性。

(私有)瀏覽器緩存
私有緩存只能用于單獨(dú)用戶。你可能已經(jīng)見過瀏覽器設(shè)置中的“緩存”選項。瀏覽器緩存擁有用戶通過 HTTP 下載的所有文檔。這些緩存為瀏覽過的文檔提供向后/向前導(dǎo)航,保存網(wǎng)頁,查看源碼等功能,可以避免再次向服務(wù)器發(fā)起多余的請求。它同樣可以提供緩存內(nèi)容的離線瀏覽。
(共享)代理緩存
共享緩存可以被多個用戶使用。例如,ISP 或你所在的公司可能會架設(shè)一個 web 代理來作為本地網(wǎng)絡(luò)基礎(chǔ)的一部分提供給用戶。這樣熱門的資源就會被重復(fù)使用,減少網(wǎng)絡(luò)擁堵與延遲。
緩存操作的目標(biāo)
雖然 HTTP 緩存不是必須的,但重用緩存的資源通常是必要的。然而常見的 HTTP 緩存只能存儲 GET 響應(yīng),對于其他類型的響應(yīng)則無能為力。緩存的關(guān)鍵主要包括request method和目標(biāo)URI(一般只有GET請求才會被緩存)。普遍的緩存案例:
一個檢索請求的成功響應(yīng): 對于 GET請求,響應(yīng)狀態(tài)碼為:200,則表示為成功。一個包含例如HTML文檔,圖片,或者文件的響應(yīng)。 永久重定向: 響應(yīng)狀態(tài)碼:301。 錯誤響應(yīng): 響應(yīng)狀態(tài)碼:404 的一個頁面。 不完全的響應(yīng): 響應(yīng)狀態(tài)碼 206,只返回局部的信息。 除了 GET 請求外,如果匹配到作為一個已被定義的cache鍵名的響應(yīng)。
針對一些特定的請求,也可以通過關(guān)鍵字區(qū)分多個存儲的不同響應(yīng)以組成緩存的內(nèi)容。
緩存控制
Cache-control 頭
HTTP/1.1定義的 Cache-Control 頭用來區(qū)分對緩存機(jī)制的支持情況, 請求頭和響應(yīng)頭都支持這個屬性。通過它提供的不同的值來定義緩存策略。
沒有緩存
緩存中不得存儲任何關(guān)于客戶端請求和服務(wù)端響應(yīng)的內(nèi)容。每次由客戶端發(fā)起的請求都會下載完整的響應(yīng)內(nèi)容。
Cache-Control: no-store
緩存但重新驗(yàn)證
如下頭部定義,此方式下,每次有請求發(fā)出時,緩存會將此請求發(fā)到服務(wù)器(譯者注:該請求應(yīng)該會帶有與本地緩存相關(guān)的驗(yàn)證字段),服務(wù)器端會驗(yàn)證請求中所描述的緩存是否過期,若未過期(注:實(shí)際就是返回304),則緩存才使用本地緩存副本。
Cache-Control: no-cache
私有和公共緩存
"public" 指令表示該響應(yīng)可以被任何中間人(譯者注:比如中間代理、CDN等)緩存。若指定了"public",則一些通常不被中間人緩存的頁面(譯者注:因?yàn)槟J(rèn)是private)(比如 帶有HTTP驗(yàn)證信息(帳號密碼)的頁面 或 某些特定狀態(tài)碼的頁面),將會被其緩存。
而 "private" 則表示該響應(yīng)是專用于某單個用戶的,中間人不能緩存此響應(yīng),該響應(yīng)只能應(yīng)用于瀏覽器私有緩存中。
Cache-Control: private
Cache-Control: public
過期
過期機(jī)制中,最重要的指令是 "max-age=<seconds>",表示資源能夠被緩存(保持新鮮)的最大時間。相對Expires而言,max-age是距離請求發(fā)起的時間的秒數(shù)。針對應(yīng)用中那些不會改變的文件,通常可以手動設(shè)置一定的時長以保證緩存有效,例如圖片、css、js等靜態(tài)資源。
Cache-Control: max-age=31536000
驗(yàn)證方式
當(dāng)使用了 "must-revalidate" 指令,那就意味著緩存在考慮使用一個陳舊的資源時,必須先驗(yàn)證它的狀態(tài),已過期的緩存將不被使用。
Cache-Control: must-revalidate
Pragma 頭
Pragma 是HTTP/1.0標(biāo)準(zhǔn)中定義的一個header屬性,請求中包含Pragma的效果跟在頭信息中定義Cache-Control: no-cache相同,但是HTTP的響應(yīng)頭沒有明確定義這個屬性,所以它不能拿來完全替代HTTP/1.1中定義的Cache-control頭。通常定義Pragma以向后兼容基于HTTP/1.0的客戶端。
理論上來講,當(dāng)一個資源被緩存存儲后,該資源應(yīng)該可以被永久存儲在緩存中。由于緩存只有有限的空間用于存儲資源副本,所以緩存會定期地將一些副本刪除,這個過程叫做緩存驅(qū)逐。另一方面,當(dāng)服務(wù)器上面的資源進(jìn)行了更新,那么緩存中的對應(yīng)資源也應(yīng)該被更新,由于HTTP是C/S模式的協(xié)議,服務(wù)器更新一個資源時,不可能直接通知客戶端更新緩存,所以雙方必須為該資源約定一個過期時間,在該過期時間之前,該資源(緩存副本)就是新鮮的,當(dāng)過了過期時間后,該資源(緩存副本)則變?yōu)殛惻f的。驅(qū)逐算法用于將陳舊的資源(緩存副本)替換為新鮮的,注意,一個陳舊的資源(緩存副本)是不會直接被清除或忽略的,當(dāng)客戶端發(fā)起一個請求時,緩存檢索到已有一個對應(yīng)的陳舊資源(緩存副本),則緩存會先將此請求附加一個If-None-Match頭,然后發(fā)給目標(biāo)服務(wù)器,以此來檢查該資源副本是否是依然還是算新鮮的,若服務(wù)器返回了 304 (Not Modified)(該響應(yīng)不會有帶有實(shí)體信息),則表示此資源副本是新鮮的,這樣一來,可以節(jié)省一些帶寬。若服務(wù)器通過 If-None-Match 或 If-Modified-Since判斷后發(fā)現(xiàn)已過期,那么會帶有該資源的實(shí)體內(nèi)容返回。

對于含有特定頭信息的請求,會去計算緩存壽命。比如Cache-control: max-age=N的頭,相應(yīng)的緩存的壽命就是N。通常情況下,對于不含這個屬性的請求則會去查看是否包含Expires屬性,通過比較Expires的值和頭里面Date屬性的值來判斷是否緩存還有效。如果max-age和expires屬性都沒有,找找頭里的Last-Modified信息。如果有,緩存的壽命就等于頭里面Date的值減去Last-Modified的值除以10
緩存失效時間計算公式如下:
expirationTime = responseTime + freshnessLifetime - currentAge
上式中,responseTime 表示瀏覽器接收到此響應(yīng)的那個時間點(diǎn)。
改進(jìn)資源
我們使用緩存的資源越多,網(wǎng)站的響應(yīng)能力和性能就會越好。為了優(yōu)化緩存,過期時間設(shè)置得盡量長是一種很好的策略。對于定期或者頻繁更新的資源,這么做是比較穩(wěn)妥的,但是對于那些長期不更新的資源會有點(diǎn)問題。這些固定的資源在一定時間內(nèi)受益于這種長期保持的緩存策略,但一旦要更新就會很困難。特指網(wǎng)頁上引入的一些js/css文件,當(dāng)它們變動時需要盡快更新線上資源。
web開發(fā)者發(fā)明了一種被 Steve Souders 稱之為 revving 的技術(shù) 。不頻繁更新的文件會使用特定的命名方式:在URL后面(通常是文件名后面)會加上版本號。加上版本號后的資源就被視作一個完全新的獨(dú)立的資源,同時擁有一年甚至更長的緩存過期時長。但是這么做也存在一個弊端,所有引用這個資源的地方都需要更新鏈接。web開發(fā)者們通常會采用自動化構(gòu)建工具在實(shí)際工作中完成這些瑣碎的工作。當(dāng)?shù)皖l更新的資源(js/css)變動了,只用在高頻變動的資源文件(html)里做入口的改動。
這種方法還有一個好處:同時更新兩個緩存資源不會造成部分緩存先更新而引起新舊文件內(nèi)容不一致。對于互相有依賴關(guān)系的css和js文件,避免這種不一致性是非常重要的。

緩存驗(yàn)證
用戶點(diǎn)擊刷新按鈕時會開始緩存驗(yàn)證。如果緩存的響應(yīng)頭信息里含有"Cache-control: must-revalidate”的定義,在瀏覽的過程中也會觸發(fā)緩存驗(yàn)證。另外,在瀏覽器偏好設(shè)置里設(shè)置Advanced->Cache為強(qiáng)制驗(yàn)證緩存也能達(dá)到相同的效果。
當(dāng)緩存的文檔過期后,需要進(jìn)行緩存驗(yàn)證或者重新獲取資源。只有在服務(wù)器返回強(qiáng)校驗(yàn)器或者弱校驗(yàn)器時才會進(jìn)行驗(yàn)證。
ETags
作為緩存的一種強(qiáng)校驗(yàn)器,ETag 響應(yīng)頭是一個對用戶代理(User Agent, 下面簡稱UA)不透明(譯者注:UA 無需理解,只需要按規(guī)定使用即可)的值。對于像瀏覽器這樣的HTTP UA,不知道ETag代表什么,不能預(yù)測它的值是多少。如果資源請求的響應(yīng)頭里含有ETag, 客戶端可以在后續(xù)的請求的頭中帶上 If-None-Match 頭來驗(yàn)證緩存。
Last-Modified 響應(yīng)頭可以作為一種弱校驗(yàn)器。說它弱是因?yàn)樗荒芫_到一秒。如果響應(yīng)頭里含有這個信息,客戶端可以在后續(xù)的請求中帶上 If-Modified-Since 來驗(yàn)證緩存。
當(dāng)向服務(wù)端發(fā)起緩存校驗(yàn)的請求時,服務(wù)端會返回 200 ok表示返回正常的結(jié)果或者 304 Not Modified(不返回body)表示瀏覽器可以使用本地緩存文件。304的響應(yīng)頭也可以同時更新緩存文檔的過期時間。
Vary 響應(yīng)
Vary HTTP 響應(yīng)頭決定了對于后續(xù)的請求頭,如何判斷是請求一個新的資源還是使用緩存的文件。
當(dāng)緩存服務(wù)器收到一個請求,只有當(dāng)前的請求和原始(緩存)的請求頭跟緩存的響應(yīng)頭里的Vary都匹配,才能使用緩存的響應(yīng)。

使用vary頭有利于內(nèi)容服務(wù)的動態(tài)多樣性。例如,使用Vary: User-Agent頭,緩存服務(wù)器需要通過UA判斷是否使用緩存的頁面。如果需要區(qū)分移動端和桌面端的展示內(nèi)容,利用這種方式就能避免在不同的終端展示錯誤的布局。另外,它可以幫助 Google 或者其他搜索引擎更好地發(fā)現(xiàn)頁面的移動版本,并且告訴搜索引擎沒有引入Cloaking。
Vary: User-Agent
因?yàn)橐苿影婧妥烂娴目蛻舳说恼埱箢^中的User-Agent不同, 緩存服務(wù)器不會錯誤地把移動端的內(nèi)容輸出到桌面端到用戶。
跨源資源共享(
CORS)
跨源資源共享 (CORS) (或通俗地譯為跨域資源共享)是一種基于HTTP 頭的機(jī)制,該機(jī)制通過允許服務(wù)器標(biāo)示除了它自己以外的其它origin(域,協(xié)議和端口),這樣瀏覽器可以訪問加載這些資源。跨源資源共享還通過一種機(jī)制來檢查服務(wù)器是否會允許要發(fā)送的真實(shí)請求,該機(jī)制通過瀏覽器發(fā)起一個到服務(wù)器托管的跨源資源的"預(yù)檢"請求。在預(yù)檢中,瀏覽器發(fā)送的頭中標(biāo)示有HTTP方法和真實(shí)請求中會用到的頭。
跨源HTTP請求的一個例子:運(yùn)行在 http://domain-a.com 的JavaScript代碼使用XMLHttpRequest來發(fā)起一個到 https://domain-b.com/data.json 的請求。
出于安全性,瀏覽器限制腳本內(nèi)發(fā)起的跨源HTTP請求。例如,XMLHttpRequest和Fetch API遵循同源策略。這意味著使用這些API的Web應(yīng)用程序只能從加載應(yīng)用程序的同一個域請求HTTP資源,除非響應(yīng)報文包含了正確CORS響應(yīng)頭。

什么情況下需要 CORS ?
前文提到的由 XMLHttpRequest或Fetch發(fā)起的跨源HTTP請求。Web字體 (CSS中通過@font-face使用跨源字體資源)WebGL貼圖使用 drawImage將Images/video畫面繪制到canvas
功能概述
跨源資源共享標(biāo)準(zhǔn)新增了一組 HTTP 首部字段,允許服務(wù)器聲明哪些源站通過瀏覽器有權(quán)限訪問哪些資源。另外,規(guī)范要求,對那些可能對服務(wù)器數(shù)據(jù)產(chǎn)生副作用的 HTTP 請求方法(特別是 GET 以外的 HTTP 請求,或者搭配某些 MIME 類型的 POST 請求),瀏覽器必須首先使用 OPTIONS 方法發(fā)起一個預(yù)檢請求(preflight request),從而獲知服務(wù)端是否允許該跨源請求。服務(wù)器確認(rèn)允許之后,才發(fā)起實(shí)際的 HTTP 請求。在預(yù)檢請求的返回中,服務(wù)器端也可以通知客戶端,是否需要攜帶身份憑證(包括 Cookies 和 HTTP 認(rèn)證相關(guān)數(shù)據(jù))。
CORS請求失敗會產(chǎn)生錯誤,但是為了安全,在JavaScript代碼層面是無法獲知到底具體是哪里出了問題。你只能查看瀏覽器的控制臺以得知具體是哪里出現(xiàn)了錯誤。
跨源資源共享機(jī)制的工作原理
Accept
Accept-Language
Content-Language
Content-Type (需要注意額外的限制)
DPR
Downlink
Save-Data
Viewport-Width
Width
Content-Type 的值僅限于下列三者之一:
text/plain
multipart/form-data
application/x-www-form-urlencoded
跨源資源共享機(jī)制的工作原理: 使用 XMLHttpRequest 對象。
示例:
var invocation = new XMLHttpRequest();
var url = 'http://xx.other/resources/public-data/';
function callOtherDomain() {
if(invocation) {
invocation.open('GET', url, true);
invocation.onreadystatechange = handler;
invocation.send();
}
}
客戶端和服務(wù)器之間使用 CORS 首部字段來處理權(quán)限:

GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent:
Accept:
Accept-Language:
Accept-Encoding:
Accept-Charset:
Connection:
Referer:
Origin:
HTTP/1.1 200 OK
Date:
Server:
Access-Control-Allow-Origin: *
Keep-Alive:
Connection:
Transfer-Encoding:
Content-Type:
預(yù)檢請求
可以避免跨域請求對服務(wù)器的用戶數(shù)據(jù)產(chǎn)生未預(yù)期的影響。
OPTIONS /resources/post-here/ HTTP/1.1
Host:
User-Agent:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Origin:
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
HTTP/1.1 200 OK
Date:
Server:
Access-Control-Allow-Origin:
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers:
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
預(yù)檢請求完成之后,發(fā)送實(shí)際請求。
預(yù)檢請求中同時攜帶了下面兩個首部字段:
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Methods 表明服務(wù)器允許客戶端使用 POST, GET 和 OPTIONS 方法發(fā)起請求。
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
首部字段 Access-Control-Allow-Headers 表明服務(wù)器允許請求中攜帶字段 X-PINGOTHER 與 Content-Type。
附帶身份憑證的請求
示例:可以基于 HTTP cookies 和 HTTP 認(rèn)證信息發(fā)送身份憑證。
var invocation = new XMLHttpRequest();
var url = 'http://xxxx.other/resources/credentialed-content/';
function callOtherDomain(){
if(invocation) {
invocation.open('GET', url, true);
//向服務(wù)器發(fā)送 Cookies
invocation.withCredentials = true;
invocation.onreadystatechange = handler;
invocation.send();
}
}
如果服務(wù)器端的響應(yīng)中未攜帶 Access-Control-Allow-Credentials: true ,瀏覽器將不會把響應(yīng)內(nèi)容返回給請求的發(fā)送者。

附帶身份憑證的請求與通配符
對于附帶身份憑證的請求,服務(wù)器不得設(shè)置 Access-Control-Allow-Origin 的值為“*”。
這是因?yàn)檎埱蟮氖撞恐袛y帶了 Cookie 信息,如果 Access-Control-Allow-Origin 的值為“*”,請求將會失敗。而將 Access-Control-Allow-Origin 的值設(shè)置為 http://foo.example,則請求將成功執(zhí)行。
另外,響應(yīng)首部中也攜帶了 Set-Cookie 字段,嘗試對 Cookie 進(jìn)行修改。如果操作失敗,將會拋出異常。
第三方 cookies
注意在 CORS 響應(yīng)中設(shè)置的 cookies 適用一般性第三方 cookie 策略。
HTTP響應(yīng)首部字段
Access-Control-Allow-Origin: <origin> | *
其中,origin 參數(shù)的值指定了允許訪問該資源的外域 URI。對于不需要攜帶身份憑證的請求,服務(wù)器可以指定該字段的值為通配符,表示允許來自所有域的請求。
在跨源訪問時,XMLHttpRequest對象的getResponseHeader()方法只能拿到一些最基本的響應(yīng)頭,Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,如果要訪問其他頭,則需要服務(wù)器設(shè)置本響應(yīng)頭。
Access-Control-Expose-Headers 頭讓服務(wù)器把允許瀏覽器訪問的頭放入白名單,例如:
Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
這樣瀏覽器就能夠通過getResponseHeader訪問X-My-Custom-Header和 X-Another-Custom-Header 響應(yīng)頭了。
指定了preflight請求的結(jié)果能夠被緩存多久
Access-Control-Max-Age: <delta-seconds>
delta-seconds 參數(shù)表示preflight請求的結(jié)果在多少秒內(nèi)有效。
Access-Control-Allow-Credentials
Access-Control-Allow-Credentials 頭指定了當(dāng)瀏覽器的credentials設(shè)置為true時是否允許瀏覽器讀取response的內(nèi)容。
當(dāng)用在對preflight預(yù)檢測請求的響應(yīng)中時,它指定了實(shí)際的請求是否可以使用credentials。請注意:簡單 GET 請求不會被預(yù)檢;如果對此類請求的響應(yīng)中不包含該字段,這個響應(yīng)將被忽略掉,并且瀏覽器也不會將相應(yīng)內(nèi)容返回給網(wǎng)頁。
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods 首部字段用于預(yù)檢請求的響應(yīng)。其指明了實(shí)際請求所允許使用的 HTTP 方法。
Access-Control-Allow-Headers 首部字段用于預(yù)檢請求的響應(yīng)。其指明了實(shí)際請求中允許攜帶的首部字段。
Access-Control-Request-Method 首部字段用于預(yù)檢請求。其作用是,將實(shí)際請求所使用的 HTTP 方法告訴服務(wù)器。
Access-Control-Request-Headers 首部字段用于預(yù)檢請求。其作用是,將實(shí)際請求所攜帶的首部字段告訴服務(wù)器。
??關(guān)注+點(diǎn)贊+收藏+評論+轉(zhuǎn)發(fā)??,原創(chuàng)不易,鼓勵筆者創(chuàng)作更好的文章
點(diǎn)贊、收藏和評論
我是Jeskson(達(dá)達(dá)前端),感謝各位人才的:點(diǎn)贊、收藏和評論,我們下期見!(如本文內(nèi)容有地方講解有誤,歡迎指出?謝謝,一起學(xué)習(xí)了)
我們下期見!
github收錄,歡迎Star:https://github.com/webVueBlog/WebFamily
