请求头部带Token -- node.js Express模拟CORS

1.什么是跨域?

通过XHR实现Ajax通信的一个主要限制,来源于跨域安全策略,默认情况下,XHR对象只能访问与包含它的页面位于同一个域中的资源,这种安全策略可以预防某些恶意行为。

2.什么是CORS?

CORS(Cross-Origin Resource Sharing) -- 跨域资源共享,W3C的工作草案,定义了在必须访问跨域资源时,浏览器与服务器该如何进行沟通,CORS背后的基本思想就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或者相应是成功还是失败。

正文:

在某些条件下,请求后台需要在headers中添加Token用以鉴权,这个时候需要CORS来帮忙,这里使用Node.js的Express来模拟后台配置响应头,使得将Token放入headers变为可行:

首先新建文件夹,并安装express:

npm install express

然后新建入口index.js、测试请求index.html

index.js:

const express = require('express');
const app = express()
app.listen(3300,()=>console.log('启动服务'));
app.post('/post',(req,res)=>{
   let resObj = {
      msg:"CORS",
      headers:req.headers
   }
   res.json(resObj )
})

简单启动了一个端口为3300的服务,定义post请求一半公开侧事故

index.html:

    //引用于JavaScript高级程序设计的兼容性xhr写法  
    function createXHR() {
         if (typeof XMLHttpRequest != 'undefined') {
            return new XMLHttpRequest();
         } else if (typeof ActiveXObject != 'undefined') {
            if (typeof arguments.callee.activeXString != 'string') {
               var versions = [
                     'MSXML2 .XMLHttp.6.0', 'MSXML2.XMLHttp.3.0',
                     'MSXML2.XMLHttp'
                  ],
                  i, len;
               for (i = 0, len = versions.length; i < len; i++) {
                  try {
                     new ActiveXObject(versions[i]);
                     arguments.callee.activeXString = versions[i];
                     break;
                  } catch (ex) {
                     // pass;
                  }
               }
               return new ActiveXObject(arguments.callee.activeXString);
            } else {
               throw new Error('no XHR Object')
            }
         }
      }
      //简单封装ajax 传入url,headers,data
      function ajax(url, headers, data) {
         return new Promise((resolve, reject) => {
            var xhr = createXHR();
            xhr.onreadystatechange = function () {
               if (xhr.readyState == 4) {
                  if ((xhr.readyState >= 200 && xhr.status < 300) || xhr.status == 304) {
                     resolve(xhr.responseText);
                  } else {
                     reject(xhr.status)
                     console.log('Request was unsuccessful: ' + xhr.status)
                  }
               }
            };
            xhr.open('post', url, true);
            if (headers) {
               headers.forEach(element => {
                  let {
                     name,
                     value
                  } = element;
                  xhr.setRequestHeader(name, value);
               });
            }
            xhr.send(data)
         })

      }
      //测试用 随便写的
      var data = new FormData();
      data.append('name', 'Nicholas');
      let url = 'http://127.0.0.1:3300/post'
      // 设置头 将Token带入
      let headers = [
         {
            name: "Token",
            value: "XXX3RT-AASDR-FFDSX-RRESA"
         }
      ]
      //调用
      ajax(url, headers, data).then(res => {
         console.log(res)
      }).catch(e => {
         console.log(e)
      })

这里简单写了一个Ajax并将token放入headers,这个时候如果向测试口发请求:

首先会报跨域错误:未设置Access-Control-Allow-Origin头,现在在index.js中把头加上:

const express = require('express');
const app = express()
app.listen(3300,()=>console.log('启动服务'));
//express中间件
app.use("*",(req,res,next)=>{
   // 允许任意源
   res.header('Access-Control-Allow-Origin',"*");
   next();
})
app.post('/post',(req,res)=>{
   let resObj = {
      msg:"CORS",
      headers:req.headers
   }
   res.json(resObj )
})

这个时候再请求:

会出现另一个跨域错误:不允许我们更改请求头,这是因为:

跨域的XHR存在一些限制:

  1. 不能使用setRequestHeader()设置自定义头部
  2. 不能发送和接收cookie
  3. 调用getAllResponseHeaders()方法总会返回空字符串

3.Preflighted Requests

CORS通过这个透明服务验证机制支持开发人员用自定义头部、GET,POST以外的方法,以及不同类型的主体内容,在使用这些类项来发送请求时,就会向服务器发送一个Preflight请求,这种请求使用OPTIONS方法。

这就需要我们在index.js中通过响应与浏览器进行沟通:

const express = require('express');
const app = express()
app.listen(3300,()=>console.log('启动服务'));
// 中间件
app.use("*",(req,res,next)=>{
   // 允许任意源
   res.header('Access-Control-Allow-Origin',"*");
   // 允许的请求方法 修改请求头时会发送预检请求
   res.header('Access-Control-Allow-Methods','GET,POST,OPTIONS')
   // 允许自定义头部
   res.header('Access-Control-Allow-Headers',"Token");
   // 收到遇见请求返回成功状态
   if(req.method == 'OPTIONS'){
      res.send(200)
   }else{
      next();
   }
})
app.post('/post',(req,res)=>{
   let resObj = {
      msg:"CORS",
      headers:req.headers
   }
   res.json(resObj )
})

将这些响应设置好以后我们再请求,首先看一下netWork:

发现发送了两次请求:

第一次为OPTIONS:

请求头部带Token -- node.js Express模拟CORS_第1张图片

第二次为真正的POST请求:

请求头部带Token -- node.js Express模拟CORS_第2张图片

请求成功,并且Token带入了headers,至此完成了模拟CORS头部带Token请求的写法.

注:如果在index.js的中间件中增加:

   res.header('Access-Control-Max-Age',1728000)

Preflight请求结束以后,结果将按照响应中指定的时间缓存起来,再次请求将不会在进行Preflight请求。

请求头部带Token -- node.js Express模拟CORS_第3张图片

参考:JavaScript高级程序设计,https://www.jianshu.com/p/f650dfad5574

你可能感兴趣的:(web前端)