天天看點

淺談CORS如何實作跨域通路

CORS全稱"跨域資源共享"(Cross-origin resource sharing)。

跨域資源共享是一份浏覽器技術的規範,以避開浏覽器的同源政策

CORS約定伺服器端和浏覽器在HTTP協定之上,通過一些額外HTTP頭部資訊,進行跨域資源共享的協商。伺服器端和浏覽器都必需遵循規範中的要求。

XMLHttpRequest支援通過withCredentials屬性實作在跨域請求攜帶身份資訊(Credential,例如Cookie或者HTTP認證資訊)。浏覽器将攜帶Cookie Header的請求發送到伺服器端後,如果伺服器沒有響應Access-Control-Allow-Credentials Header,那麼浏覽器會忽略掉這次響應。

Ajax XMLHttpRequest對象發起請求,所有的CORS HTTP請求頭都可以由浏覽器填充,無需在XMLHttpRequest對象中設定。

下面是CORS協定規定的HTTP頭,用來進行浏覽器發起跨域資源請求時進行協商:

  1. Origin

    。HTTP請求頭,任何涉及CORS的請求都必需攜帶。
  2. Access-Control-Request-Methods

    。HTTP請求頭,在帶預檢(Preflighted)的跨域請求中用來表示真實請求的方法。
  3. Access-Control-Request-Headers

    。HTTP請求頭,在帶預檢(Preflighted)的跨域請求中用來表示真實請求的自定義Header清單。
  4. Access-Control-Allow-Origin

    。HTTP響應頭,指定伺服器端允許進行跨域資源通路的來源域。可以用通配符*表示允許任何域的JavaScript通路資源,但是在響應一個攜帶身份資訊(Credential)的HTTP請求時,Access-Control-Allow-Origin必需指定具體的域,不能用通配符。
  5. Access-Control-Allow-Methods

    。HTTP響應頭,指定伺服器允許進行跨域資源通路的請求方法清單,一般用在響應預檢請求上。
  6. Access-Control-Allow-Headers

    。HTTP響應頭,指定伺服器允許進行跨域資源通路的請求頭清單,一般用在響應預檢請求上。
  7. Access-Control-Max-Age

    。HTTP響應頭,用在響應預檢請求上,表示本次預檢響應的有效時間。在此時間内,浏覽器都可以根據此次協商結果決定是否有必要直接發送真實請求,而無需再次發送預檢請求。
  8. Access-Control-Allow-Credentials

    。HTTP響應頭,凡是浏覽器請求中攜帶了身份資訊,而響應頭中沒有傳回Access-Control-Allow-Credentials: true的,浏覽器都會忽略此次響應。

模拟服務端口為3000的用戶端

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>3000端口</title>
</head>
<body>
    <button class="btn1">非跨域(同源)請求</button>
    <button class="btn2">跨域(非同源)請求</button>
    <script>

        // 非跨域請求
        //當我們通過XMLHttpRequest對象向端口為3000的服務端發起請求時,請求成功并擷取字元串資料:"同源通路3000端口"
        document.querySelector(".btn1").onclick = function(){
            let xhr = new XMLHttpRequest();
            xhr.open("post","/post",true);
            xhr.onload = function(){
                console.log(xhr.responseText);
            }
            xhr.send();
        }

        // 跨域請求(說請求成功了,但沒拿到資料)
        document.querySelector(".btn2").onclick = function(){
            let xhr = new XMLHttpRequest();  
             // 跨域請求時,請求url不能是相對路徑了,寫法如下:
            xhr.open("post","http://localhost:4000/post",true);

            xhr.onload = function(){
                console.log(xhr.responseText);
                // 擷取傳回頭部資訊
                let res = xhr.getAllResponseHeaders();
                console.log(res);
            }
            xhr.send();
        }
    </script>
</body>
</html>
           

模拟服務端口為3000的服務端

indexOne.js

//  服務端口在3000
const Koa = require("koa");
const static = require("koa-static");
const Router = require("koa-router");

let app = new Koa();
let router = new Router();

app.use(static(__dirname+"/static"));

router.get("/",ctx=>{
    ctx.body = "3000端口";
});
router.post("/post",ctx=>{
    ctx.body = "同源通路3000端口";
});
app.use(router.routes());
app.listen(3000);
           

模拟服務端口為4000的服務端

indexTwo.js

// 服務端口在4000
const Koa = require("koa");
const static = require("koa-static");
const Router = require("koa-router");

let app = new Koa();
let router = new Router();

app.use(static(__dirname+"/static"));

router.get("/",ctx=>{
    ctx.body = "4000端口";
})
router.post("/post",ctx=>{
    ctx.body = "非同源通路4000端口";
});

app.use(router.routes());
app.listen(4000);
           

我們直接運作上面代碼後,我們看到,同源的用戶端通路服務端,成功了并拿到了資料。而非同源的用戶端通路不同端口的服務端(即服務端口為3000的用戶端直接去通路端口為4000伺服器)就報錯了,并沒有拿到資料,這就涉及到了跨域問題!

淺談CORS如何實作跨域通路

"同源政策"是浏覽器規定的,是以我們對上面的代碼改動一下,在端口為4000服務端對cors設定http頭部進行相關設定。

router.post("/post",ctx=>{
    ctx.body = "非同源通路4000端口";
    // 對http頭部資訊進行相應的設定
    // 允許跨域通路(表明來自哪裡的跨域請求),必須設定
    // (1)"*"号表示允許任何域向我們的服務端送出請求:
    //     ctx.set("Access-Control-Allow-Origin:*")
    // (2)在響應一個攜帶身份資訊(Credential)的HTTP請求時,
    //    必需指定具體的域名,不能用通配符"*"。如下:
    // 允許服務端口為3000的站點進行跨域通路
    ctx.set("Access-Control-Allow-Origin","http://localhost:3000");

    // 允許擷取頭部資訊
    ctx.set("Access-Control-Expose-Headers","Content-Type,X-Requested-With,token");

    //設定允許前端發送的請求方式(CORS支援多種請求方式)
    ctx.set("Access-Control-Allow-Methods","GET,POST,PUT,DELETE,OPTIONS");
});
           

如下圖,跨域請求成功,并擷取了字元串資料"非同源通路4000端口"

淺談CORS如何實作跨域通路

如下圖,跨域通路成功後,從控制台可以檢視到Response Headers下,一些http請求的一些相應的頭部資訊

淺談CORS如何實作跨域通路