請求頭部帶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:

第二次爲真正的POST請求:

請求成功,並且Token帶入了headers,至此完成了模擬CORS頭部帶Token請求的寫法.

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

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

Preflight請求結束以後,結果將按照響應中指定的時間緩存起來,再次請求將不會在進行Preflight請求。

參考:JavaScript高級程序設計,https://www.jianshu.com/p/f650dfad5574

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章