浅谈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


<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服务器)就报错了,并没有拿到数据,这就涉及到了跨域问题!
在这里插入图片描述
"同源策略"是浏览器规定的,所以我们对上面的代码改动一下,在端口为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端口"
在这里插入图片描述
如下图,跨域访问成功后,从控制台可以查看到Response Headers下,一些http请求的一些相应的头部信息
浅谈CORS如何实现跨域访问_第1张图片

你可能感兴趣的:(跨域访问,NodeJS)