1. 程式人生 > 實用技巧 >HTTP系列之跨域資源共享機制(CORS)介紹

HTTP系列之跨域資源共享機制(CORS)介紹

前言

本文將繼續解析詳解HTTP系列1中的請求/ 響應報文的首部欄位,今天帶來的跨域資源共享(CORS)機制,具體內容包括CORS的原理、流程、實戰,希望能給大家帶來收穫!



CORS簡介

跨域資源共享(CORS)是一種機制,它使用額外的 HTTP 頭來告訴瀏覽器 讓執行在一個 origin (domain) 上的Web應用被准許訪問來自不同源伺服器上的指定的資源。當一個資源從與該資源本身所在的伺服器不同的域、協議或埠請求一個資源時,此請求就是一個跨域 HTTP 請求

出於安全原因,瀏覽器限制從指令碼內發起的跨源HTTP請求(或者是返回結果被瀏覽器攔截)。因為要確保後臺傳遞過來資料的可靠性,就必須前後端關於CORS的設定是一致的,而解決此方法要麼是後臺放開跨域限制,要麼是前端被動配合後臺(這往往與業務不符合)。



兩類CORS

根據瀏覽器與後臺互動邏輯的不同,CORS一般可分為兩類:
 

簡單請求

滿足條件:

  1. 請求方法是以下三種方法之一: HEAD , GET , POST
  2. HTTP的頭部資訊不超過一下幾種欄位:
    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type:只限於三個值application/x-www-form-urlencodedmultipart/form-datatext/plain

基本流程:

  1. 瀏覽器判斷請求是簡單請求,自動在頭資訊之中,新增一個Origin欄位,包含了請求來自的源(協議+域名+埠);
  2. 伺服器根據這個值,決定是否同意這次請求(根據已有配置)。如果是在許可範圍內,則返回正確HTTP響應並附帶``Access-Control-Allow-Origin的`等頭部欄位資訊,瀏覽器正常執行;如果不帶這類欄位,則瀏覽器會報錯;
  3. 如果跨域被禁,丟擲的錯誤會被XMLHttpRequest物件的onerror函式捕獲,下同。

 

預檢請求

不是簡單請求則都是預檢請求。

基本流程:

  1. 非簡單請求的CORS請求,會在正式通訊之前,增加一次HTTP查詢請求,稱為"預檢"請求(preflight)。

  2. 瀏覽器先詢問伺服器,當前網頁所在的域名是否在伺服器的許可名單之中,以及可以使用哪些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。