當(dāng)加上 CORS 之后,從發(fā)起到請求正式成功一般會經(jīng)歷以下過程:
簡單請求(以 GET、POST 等簡單方法且無特殊請求頭的請求為例)
-
發(fā)起請求:客戶端(通常是瀏覽器)向跨域的服務(wù)器發(fā)送請求,例如使用
fetch
或XMLHttpRequest
等 API。請求頭中會包含Origin
字段,它表示請求發(fā)起的源,包括協(xié)議、域名和端口號。 -
服務(wù)器接收請求:服務(wù)器接收到請求后,會檢查
Origin
字段。然后根據(jù)自身的 CORS 配置,判斷該源是否被允許訪問。 -
服務(wù)器響應(yīng):如果
Origin
是允許的,服務(wù)器會在響應(yīng)頭中添加Access - Control - Allow - Origin
字段,其值為允許的源(可以是具體的源,也可能是*
表示允許所有源)。同時(shí),可能還會添加其他相關(guān)的 CORS 響應(yīng)頭,如Access - Control - Allow - Credentials
(如果涉及到跨域攜帶憑證)等。然后將響應(yīng)數(shù)據(jù)發(fā)送給客戶端。 -
客戶端處理響應(yīng):瀏覽器接收到響應(yīng)后,檢查
Access - Control - Allow - Origin
等 CORS 相關(guān)頭信息。如果這些頭信息表明請求是被允許的,瀏覽器就會正常處理響應(yīng)數(shù)據(jù),將其傳遞給前端應(yīng)用程序進(jìn)行進(jìn)一步處理和展示。
復(fù)雜請求(如 PUT、DELETE 方法或帶有自定義請求頭的請求)
發(fā)起預(yù)檢請求(OPTIONS) :客戶端首先會發(fā)送一個(gè)預(yù)檢請求,使用
OPTIONS
方法。請求頭中包含Origin
字段,同時(shí)還會有Access - Control - Request - Method
字段,用于告知服務(wù)器實(shí)際請求將使用的方法(如PUT
、DELETE
等),以及Access - Control - Request - Headers
字段,列出實(shí)際請求中會包含的自定義請求頭。服務(wù)器接收預(yù)檢請求:服務(wù)器接收到預(yù)檢請求后,根據(jù)自身的 CORS 配置,檢查
Origin
以及Access - Control - Request - Method
和Access - Control - Request - Headers
字段,判斷是否允許該請求。服務(wù)器響應(yīng)預(yù)檢請求:如果允許,服務(wù)器會在響應(yīng)頭中添加
Access - Control - Allow - Origin
字段,指定允許的源。同時(shí),還會添加Access - Control - Allow - Methods
字段,列出允許的請求方法;Access - Control - Allow - Headers
字段,列出允許的請求頭。此外,還可能有Access - Control - Max - Age
字段,指定預(yù)檢請求的結(jié)果可以被緩存的時(shí)長(以秒為單位)。客戶端處理預(yù)檢響應(yīng):瀏覽器接收到預(yù)檢響應(yīng)后,檢查 CORS 相關(guān)頭信息。如果預(yù)檢請求被允許,瀏覽器會繼續(xù)發(fā)起實(shí)際的請求。
發(fā)起實(shí)際請求:客戶端按照正常流程發(fā)起實(shí)際的跨域請求,方法和請求頭與預(yù)檢請求中聲明的一致。
服務(wù)器接收和響應(yīng)實(shí)際請求:服務(wù)器接收實(shí)際請求,處理并返回響應(yīng),響應(yīng)頭中同樣會包含
Access - Control - Allow - Origin
等 CORS 相關(guān)頭信息,客戶端根據(jù)這些頭信息來決定是否處理響應(yīng)數(shù)據(jù)。
在整個(gè)過程中,CORS 機(jī)制通過請求頭和響應(yīng)頭的交互,讓服務(wù)器能夠明確告知瀏覽器哪些跨域請求是被允許的,從而實(shí)現(xiàn)了在遵循同源策略的基礎(chǔ)上,安全地進(jìn)行跨域資源訪問。
怎么用CORS實(shí)現(xiàn)跨域
以下是使用 CORS(跨域資源共享) 實(shí)現(xiàn)跨域的完整方案,涵蓋服務(wù)端配置、前端請求細(xì)節(jié)及常見問題處理:
一、CORS 核心機(jī)制
CORS 通過服務(wù)端設(shè)置 HTTP 響應(yīng)頭,告知瀏覽器允許特定頁面的跨域請求。瀏覽器根據(jù)響應(yīng)頭決定是否放行跨域請求。
二、服務(wù)端配置
1. 基礎(chǔ)響應(yīng)頭設(shè)置
在服務(wù)端響應(yīng)中添加以下頭信息(以 Node.js 為例):
// Express 中間件示例
app.use((req, res, next) => {
// 允許的源(根據(jù)需求替換為具體域名)
res.setHeader('Access-Control-Allow-Origin', 'https://your-frontend.com');
// 允許的請求方法
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
// 允許的請求頭(需明確列出)
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
// 允許攜帶 Cookie(如需)
res.setHeader('Access-Control-Allow-Credentials', 'true');
// 預(yù)檢請求緩存時(shí)間(秒)
res.setHeader('Access-Control-Max-Age', '86400');
next();
});
2. 處理預(yù)檢請求(OPTIONS)
對于非簡單請求(如 Content-Type: application/json
),瀏覽器會先發(fā)送 OPTIONS
預(yù)檢請求:
// 單獨(dú)處理 OPTIONS 請求
app.options('*', (req, res) => {
res.sendStatus(200);
});
三、前端請求配置
1. 簡單請求(Simple Request)
滿足以下條件時(shí),瀏覽器直接發(fā)送請求:
-
方法為
GET
/POST
/HEAD
-
頭信息僅含:
Accept
、Accept-Language
、Content-Language
、Content-Type
(值限于text/plain
、multipart/form-data
、application/x-www-form-urlencoded
)
示例:
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data));
2. 復(fù)雜請求(需預(yù)檢)
對于其他請求(如 PUT
、自定義頭、Content-Type: application/json
):
fetch('https://api.example.com/data', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer xxx'
},
body: JSON.stringify({ key: 'value' })
});
3. 攜帶 Cookie
需前后端協(xié)同設(shè)置:
// 前端請求添加 credentials
fetch('https://api.example.com/data', {
credentials: 'include' // 或 'same-origin'
});
// 服務(wù)端設(shè)置
res.setHeader('Access-Control-Allow-Credentials', 'true');
// 注意:此時(shí) Access-Control-Allow-Origin 不能為 *
五、常見問題與調(diào)試
1. 錯(cuò)誤排查
-
預(yù)檢失敗:檢查
OPTIONS
響應(yīng)頭是否完整 -
頭信息不匹配:確保
Access-Control-Allow-Headers
包含所有請求頭 -
Cookie 未攜帶:檢查前端
credentials
設(shè)置和服務(wù)端Allow-Credentials
2. 瀏覽器控制臺警告
-
No 'Access-Control-Allow-Origin' header
:服務(wù)端未正確設(shè)置允許的源 -
Credentials not supported
:服務(wù)端使用Access-Control-Allow-Origin: *
但前端嘗試攜帶 Cookie
3. 工具驗(yàn)證
使用 curl
檢查響應(yīng)頭:
curl -I -X OPTIONS https://api.example.com/data
# 檢查返回的 CORS 頭信息
六、安全最佳實(shí)踐
-
限制允許的源:避免使用
Access-Control-Allow-Origin: *
,應(yīng)指定具體域名 -
縮小方法范圍:按需設(shè)置
Access-Control-Allow-Methods
-
驗(yàn)證請求頭:明確列出允許的請求頭(避免使用
*
) -
限制緩存時(shí)間:合理設(shè)置
Access-Control-Max-Age
(避免過長)
通過以上配置,CORS 可安全高效地實(shí)現(xiàn)跨域請求,是現(xiàn)代 Web 應(yīng)用的首選方案。