HTTP系列之跨域資源共享機制(CORS)介紹
前言
本文將繼續解析詳解HTTP系列1中的請求/ 響應報文的首部欄位,今天帶來的跨域資源共享(CORS)機制,具體內容包括CORS的原理、流程、實戰,希望能給大家帶來收穫!
CORS簡介
跨域資源共享(CORS)是一種機制,它使用額外的 HTTP 頭來告訴瀏覽器 讓執行在一個 origin (domain) 上的Web應用被准許訪問來自不同源伺服器上的指定的資源。當一個資源從與該資源本身所在的伺服器不同的域、協議或埠請求一個資源時,此請求就是一個跨域 HTTP 請求
出於安全原因,瀏覽器限制從指令碼內發起的跨源HTTP請求(或者是返回結果被瀏覽器攔截)。因為要確保後臺傳遞過來資料的可靠性,就必須前後端關於CORS的設定是一致的,而解決此方法要麼是後臺放開跨域限制,要麼是前端被動配合後臺(這往往與業務不符合)。
兩類CORS
根據瀏覽器與後臺互動邏輯的不同,CORS一般可分為兩類:
滿足條件:
- 請求方法是以下三種方法之一: HEAD , GET , POST
- HTTP的頭部資訊不超過一下幾種欄位:
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-Type:只限於三個值
application/x-www-form-urlencoded
、multipart/form-data
、text/plain
基本流程:
- 瀏覽器判斷請求是簡單請求,自動在頭資訊之中,新增一個
Origin
欄位,包含了請求來自的源(協議+域名+埠); - 伺服器根據這個值,決定是否同意這次請求(根據已有配置)。如果是在許可範圍內,則返回正確HTTP響應並附帶``Access-Control-Allow-Origin的`等頭部欄位資訊,瀏覽器正常執行;如果不帶這類欄位,則瀏覽器會報錯;
- 如果跨域被禁,丟擲的錯誤會被
XMLHttpRequest物件的onerror函式
捕獲,下同。
不是簡單請求則都是預檢請求。
基本流程:
-
非簡單請求的CORS請求,會在正式通訊之前,增加一次HTTP查詢請求,稱為"預檢"請求(preflight)。
-
瀏覽器先詢問伺服器,當前網頁所在的域名是否在伺服器的許可名單之中,以及可以使用哪些HTTP動詞和頭資訊欄位。只有得到肯定答覆,瀏覽器才會發出正式的
XMLHttpRequest
實戰程式碼
/**
* server.js
*/
const express = require("express");
var app = express();
app.use("/*",(req,res,next)=>{
res.header("Access-Control-Allow-Origin","*"); // 放開訪問許可權給所有地址
res.header("Access-Control-Allow-Headers","*"); // 這個也會匹配
res.header("Access-Control-Allow-Methods","PUT, POST, GET, DELETE, OPTIONS");// 這個也會匹配
res.header("X-Powered-By","3.2.1");
res.header("Content-Type","text/plain; charset=utf-8");
next();
});
app.post("/data",(req,res)=>{
res.send("回覆訊息了");
});
app.listen(8081,()=>{
console.log("listen on 8081");
});
<!--
test.html
-->
<button id="closeBtn">按鈕</button>
<script>
closeBtn.onclick = function () {
var request = new XMLHttpRequest();
request.open("POST", "http://101.200.189.128:8081/data");
request.send();
};
</script>
/**
* server.js
*/
// 修改語句為如下,其他不變
res.header("Access-Control-Allow-Origin","http://127.0.0.1");
/**
* server.js
*/
// 修改語句為如下,其他不變,
res.header("Access-Control-Allow-Origin","*"); // 放開訪客限制
<!-- test.html
-->
// 新增頭部欄位,這樣請求會變成預檢請求
request.setRequestHeader("Content-Type","application/json");
/**
* server.js
*/
// 修改語句為如下,其他不變,
// 限制訪客地址只是禁止跨域的一種,也可以限制訪問方法、限制訪問頭部欄位
res.header("Access-Control-Allow-Origin","http://127.0.0.1");
withCredentials屬性
想要傳送Cookie和HTTP認證資訊,必須在兩方同時開啟withCredentials屬性。
// 伺服器端
res.header("Access-Control-Allow-Credentials","true");
// 客戶端
request.setRequestHeader("withCredentials","true");
此外,如果要傳送Cookie,Access-Control-Allow-Origin
就不能設為星號,必須指定明確的、與請求網頁一致的域名。並且Cookie依然遵循同源政策,只有用伺服器域名設定的Cookie才會上傳,其他域名的Cookie並不會上傳,且(跨源)原網頁程式碼中的document.cookie
也無法讀取伺服器域名下的Cookie。