欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺談Koa2框架利用CORS完成跨域ajax請(qǐng)求

 更新時(shí)間:2018年03月06日 08:37:07   作者:黃天浩  
這篇文章主要介紹了淺談Koa2框架利用CORS完成跨域ajax請(qǐng)求,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

實(shí)現(xiàn)跨域ajax請(qǐng)求的方式有很多,其中一個(gè)是利用CORS,而這個(gè)方法關(guān)鍵是在服務(wù)器端進(jìn)行配置。

本文僅對(duì)能夠完成正??缬騛jax響應(yīng)的,最基本的配置進(jìn)行說(shuō)明(深層次的配置我也不會(huì))。

CORS將請(qǐng)求分為簡(jiǎn)單請(qǐng)求和非簡(jiǎn)單請(qǐng)求,可以簡(jiǎn)單的認(rèn)為,簡(jiǎn)單請(qǐng)求就是沒(méi)有加上額外請(qǐng)求頭部的get和post請(qǐng)求,并且如果是post請(qǐng)求,請(qǐng)求格式不能是application/json(因?yàn)槲覍?duì)這一塊理解不深如果錯(cuò)誤希望能有人指出錯(cuò)誤并提出修改意見(jiàn))。而其余的,put、post請(qǐng)求,Content-Type為application/json的請(qǐng)求,以及帶有自定義的請(qǐng)求頭部的請(qǐng)求,就為非簡(jiǎn)單請(qǐng)求。

簡(jiǎn)單請(qǐng)求的配置十分簡(jiǎn)單,如果只是完成響應(yīng)就達(dá)到目的的話,僅需配置響應(yīng)頭部的Access-Control-Allow-Origin即可。

如果我們?cè)趆ttp://localhost:3000 域名下想要訪問(wèn) http://127.0.0.1:3001 域名??梢宰鋈缦屡渲茫?/p>

app.use(async (ctx, next) => {
 ctx.set('Access-Control-Allow-Origin', 'http://localhost:3000');
 await next();
});

然后用ajax發(fā)起一個(gè)簡(jiǎn)單請(qǐng)求,例如post請(qǐng)求,就可以輕松的得到服務(wù)器正確響應(yīng)了。

實(shí)驗(yàn)代碼如下:

$.ajax({
  type: 'post',
  url: 'http://127.0.0.1:3001/async-post'
 }).done(data => {
  console.log(data);
})

服務(wù)器端代碼:

router.post('/async-post',async ctx => {
 ctx.body = {
 code: "1",
 msg: "succ"
 }
});

然后就能得到正確的響應(yīng)信息了。

這時(shí)候如果看一下請(qǐng)求和響應(yīng)的頭部信息,會(huì)發(fā)現(xiàn)請(qǐng)求頭部多了個(gè)origin(還有一個(gè)referer為發(fā)出請(qǐng)求的url地址),而響應(yīng)頭部多了個(gè)Access-Control-Allow-Origin。

現(xiàn)在可以發(fā)送簡(jiǎn)單請(qǐng)求了,但是要想發(fā)送非簡(jiǎn)單請(qǐng)求還是需要其他的配置。

當(dāng)?shù)谝淮伟l(fā)出非簡(jiǎn)單請(qǐng)求的時(shí)候,實(shí)際上會(huì)發(fā)出兩個(gè)請(qǐng)求,第一次發(fā)出的是preflight request,這個(gè)請(qǐng)求的請(qǐng)求方法是OPTIONS,這個(gè)請(qǐng)求是否通過(guò)決定了這一個(gè)種類的非簡(jiǎn)單請(qǐng)求是否能成功得到響應(yīng)。

為了能在服務(wù)器匹配到這個(gè)OPTIONS類型的請(qǐng)求,因此需要自己做一個(gè)中間件來(lái)進(jìn)行匹配,并給出響應(yīng)使得這個(gè)預(yù)檢能夠通過(guò)。

app.use(async (ctx, next) => {
 if (ctx.method === 'OPTIONS') {
 ctx.body = '';
 }
 await next();
});

這樣OPTIONS請(qǐng)求就能夠通過(guò)了。

如果檢查一下preflight request的請(qǐng)求頭部,會(huì)發(fā)現(xiàn)多了兩個(gè)請(qǐng)求頭。

Access-Control-Request-Method: PUT
Origin: http://localhost:3000

要通過(guò)這兩個(gè)頭部信息與服務(wù)器進(jìn)行協(xié)商,看是否符合服務(wù)器應(yīng)答條件。

很容易理解,既然請(qǐng)求頭多了兩個(gè)信息,響應(yīng)頭自然也應(yīng)該有兩個(gè)信息相對(duì)應(yīng),這兩個(gè)信息如下:

Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Methods: PUT,DELETE,POST,GET

第一條信息和origin相同因此通過(guò)。第二條信息對(duì)應(yīng)Access-Controll-Request-Method,如果在請(qǐng)求的方式包含在服務(wù)器允許的響應(yīng)方式之中,因此這條也通過(guò)。兩個(gè)約束條件都滿足了,所以可以成功的發(fā)起請(qǐng)求。

至此為止,相當(dāng)于僅僅完成了預(yù)檢,還沒(méi)發(fā)送真正的請(qǐng)求呢。

真正的請(qǐng)求當(dāng)然也成功獲得了響應(yīng),并且響應(yīng)頭如下(省略不重要部分)

Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Methods: PUT,DELETE,POST,GET

請(qǐng)求頭如下:

Origin: http://localhost:3000

這就很顯而易見(jiàn)了,響應(yīng)頭部信息是我們?cè)诜?wù)器設(shè)定的,因此是這樣。

而客戶端因?yàn)閯偛乓呀?jīng)預(yù)檢過(guò)了,所以不需要再發(fā)Access-Control-Request-Method這個(gè)請(qǐng)求頭了。

這個(gè)例子的代碼如下:

$.ajax({
   type: 'put',
   url: 'http://127.0.0.1:3001/put'
  }).done(data => {
   console.log(data);
});

服務(wù)器代碼:

app.use(async (ctx, next) => {
  ctx.set('Access-Control-Allow-Origin', 'http://localhost:3000');
  ctx.set('Access-Control-Allow-Methods', 'PUT,DELETE,POST,GET');
  await next();
});

至此我們完成了能夠正確進(jìn)行跨域ajax響應(yīng)的基本配置,還有一些可以進(jìn)一步配置的東西。

比如,到目前為止,每一次非簡(jiǎn)單請(qǐng)求都會(huì)實(shí)際上發(fā)出兩次請(qǐng)求,一次預(yù)檢一次真正請(qǐng)求,這就比較損失性能了。為了能不發(fā)預(yù)檢請(qǐng)求,可以對(duì)如下響應(yīng)頭進(jìn)行配置。

Access-Control-Max-Age: 86400

這個(gè)響應(yīng)頭的意義在于,設(shè)置一個(gè)相對(duì)時(shí)間,在該非簡(jiǎn)單請(qǐng)求在服務(wù)器端通過(guò)檢驗(yàn)的那一刻起,當(dāng)流逝的時(shí)間的毫秒數(shù)不足Access-Control-Max-Age時(shí),就不需要再進(jìn)行預(yù)檢,可以直接發(fā)送一次請(qǐng)求。

當(dāng)然,簡(jiǎn)單請(qǐng)求時(shí)沒(méi)有預(yù)檢的,因此這條代碼對(duì)簡(jiǎn)單請(qǐng)求沒(méi)有意義。

目前代碼如下:

app.use(async (ctx, next) => {
 ctx.set('Access-Control-Allow-Origin', 'http://localhost:3000');
 ctx.set('Access-Control-Allow-Methods', 'PUT,DELETE,POST,GET');
 ctx.set('Access-Control-Max-Age', 3600 * 24);
 await next();
});

到現(xiàn)在為止,可以對(duì)跨域ajax請(qǐng)求進(jìn)行響應(yīng)了,但是該域下的cookie不會(huì)被攜帶在請(qǐng)求頭中。如果想要帶著cookie到服務(wù)器,并且允許服務(wù)器對(duì)cookie進(jìn)一步設(shè)置,還需要進(jìn)行進(jìn)一步的配置。

為了便于后續(xù)的檢測(cè),我們預(yù)先在http://127.0.0.1:3001這個(gè)域名下設(shè)置兩個(gè)cookie。注意不要錯(cuò)誤把cookie設(shè)置成中文(剛才我就設(shè)置成了中文,結(jié)果報(bào)錯(cuò),半天沒(méi)找到出錯(cuò)原因)

然后我們要做兩步,第一步設(shè)置響應(yīng)頭Access-Control-Allow-Credentials為true,然后在客戶端設(shè)置xhr對(duì)象的withCredentials屬性為true。

客戶端代碼如下:

$.ajax({
   type: 'put',
   url: 'http://127.0.0.1:3001/put',
   data: {
    name: '黃天浩',
    age: 20
   },
   xhrFields: {
    withCredentials: true
   }
  }).done(data => {
   console.log(data);
  });

服務(wù)端如下:

app.use(async (ctx, next) => {
  ctx.set('Access-Control-Allow-Origin', 'http://localhost:3000');
  ctx.set('Access-Control-Allow-Methods', 'PUT,DELETE,POST,GET');
  ctx.set('Access-Control-Allow-Credentials', true);
  await next();
});

這時(shí)就可以帶著cookie到服務(wù)器了,并且服務(wù)器也可以對(duì)cookie進(jìn)行改動(dòng)。但是cookie仍是http://127.0.0.1:3001域名下的cookie,無(wú)論怎么操作都在該域名下,無(wú)法訪問(wèn)其他域名下的cookie。

現(xiàn)在為止CORS的基本功能已經(jīng)都提到過(guò)了。

一開(kāi)始我不知道怎么給Access-Control-Allow-Origin,后來(lái)經(jīng)人提醒,發(fā)現(xiàn)可以寫(xiě)一個(gè)白名單數(shù)組,然后每次接到請(qǐng)求時(shí)判斷origin是否在白名單數(shù)組中,然后動(dòng)態(tài)的設(shè)置Access-Control-Allow-Origin,代碼如下:

app.use(async (ctx, next) => {
 if (ctx.request.header.origin !== ctx.origin && whiteList.includes(ctx.request.header.origin)) {
  ctx.set('Access-Control-Allow-Origin', ctx.request.header.origin);
  ctx.set('Access-Control-Allow-Methods', 'PUT,DELETE,POST,GET');
  ctx.set('Access-Control-Allow-Credentials', true);
  ctx.set('Access-Control-Max-Age', 3600 * 24);
 }
 await next();
});

這樣就可以不用*通配符也可匹配多個(gè)origin了。

注意:ctx.origin與ctx.request.header.origin不同,ctx.origin是本服務(wù)器的域名,ctx.request.header.origin是發(fā)送請(qǐng)求的請(qǐng)求頭部的origin,二者不要混淆。

最后,我們?cè)偕晕⒄{(diào)整一下自定義的中間件的結(jié)構(gòu),防止每次請(qǐng)求都返回Access-Control-Allow-Methods以及Access-Control-Max-Age,這兩個(gè)響應(yīng)頭其實(shí)是沒(méi)有必要每次都返回的,只是第一次有預(yù)檢的時(shí)候返回就可以了。

調(diào)整后順序如下:

app.use(async (ctx, next) => {
 if (ctx.request.header.origin !== ctx.origin && whiteList.includes(ctx.request.header.origin)) {
  ctx.set('Access-Control-Allow-Origin', ctx.request.header.origin);
  ctx.set('Access-Control-Allow-Credentials', true);
 }
 await next();
});

app.use(async (ctx, next) => {
 if (ctx.method === 'OPTIONS') {
  ctx.set('Access-Control-Allow-Methods', 'PUT,DELETE,POST,GET');
  ctx.set('Access-Control-Max-Age', 3600 * 24);
  ctx.body = '';
 }
 await next();
});

這樣就減少了多余的響應(yīng)頭。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • node實(shí)現(xiàn)定時(shí)發(fā)送郵件的示例代碼

    node實(shí)現(xiàn)定時(shí)發(fā)送郵件的示例代碼

    本篇文章主要介紹了node實(shí)現(xiàn)定時(shí)發(fā)送郵件的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-08-08
  • 詳解node.js中的npm和webpack配置方法

    詳解node.js中的npm和webpack配置方法

    Node.js用c++語(yǔ)言編寫(xiě)而成的,是一個(gè)基于chrome V8引擎的javascript運(yùn)行環(huán)境。這篇文章主要介紹了詳解node.js中的npm和webpack配置,需要的朋友可以參考下
    2018-01-01
  • 使用Node.js實(shí)現(xiàn)RESTful API的示例

    使用Node.js實(shí)現(xiàn)RESTful API的示例

    Node.js可以用很少代碼簡(jiǎn)單地實(shí)現(xiàn)一個(gè)Web服務(wù),并且它有一個(gè)非?;钴S的社區(qū),通過(guò)Node出色的包管理機(jī)制(NPM)可以非常容易獲得各種擴(kuò)展支持。 對(duì)簡(jiǎn)單的應(yīng)用場(chǎng)景Node.js實(shí)現(xiàn)REST是一個(gè)非常合適的選擇。 本文介紹如何用Node.js實(shí)現(xiàn)REST服務(wù)。
    2017-08-08
  • node.js中fs\path\http模塊的使用方法詳解

    node.js中fs\path\http模塊的使用方法詳解

    Node.js是基于Chrome V8引擎的JavaScript的運(yùn)行時(shí)(運(yùn)行環(huán)境-宿主環(huán)境),下面這篇文章主要給大家介紹了關(guān)于node.js中fs\path\http模塊的使用方法,需要的朋友可以參考下
    2023-01-01
  • adm-zip-0.4.13-中文文檔詳解

    adm-zip-0.4.13-中文文檔詳解

    這篇文章主要介紹了adm-zip-0.4.13-中文文檔,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-05-05
  • 詳解express與koa中間件模式對(duì)比

    詳解express與koa中間件模式對(duì)比

    本篇文章主要介紹了詳解express與koa中間件模式對(duì)比,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-08-08
  • node.js文件上傳重命名以及移動(dòng)位置的示例代碼

    node.js文件上傳重命名以及移動(dòng)位置的示例代碼

    本篇文章主要介紹了node.js文件上傳重命名以及移動(dòng)位置的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01
  • node.js的Express服務(wù)器基本使用教程

    node.js的Express服務(wù)器基本使用教程

    express是一個(gè)開(kāi)源的node.js項(xiàng)目框架,下面這篇文章主要給大家介紹了關(guān)于node.js的Express服務(wù)器基本使用的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-01-01
  • webpack創(chuàng)建項(xiàng)目并打包的詳細(xì)流程記錄

    webpack創(chuàng)建項(xiàng)目并打包的詳細(xì)流程記錄

    webpack在前端工程領(lǐng)域起到了中流砥柱的作用,理解它的內(nèi)部實(shí)現(xiàn)機(jī)制會(huì)對(duì)你的工程建設(shè)提供很大的幫助(不論是定制功能還是優(yōu)化打包),下面這篇文章主要給大家介紹了關(guān)于webpack創(chuàng)建項(xiàng)目并打包的詳細(xì)流程,需要的朋友可以參考下
    2023-03-03
  • 使用nodejs寫(xiě)接口的詳細(xì)步驟

    使用nodejs寫(xiě)接口的詳細(xì)步驟

    這篇文章主要給大家介紹了關(guān)于使用nodejs寫(xiě)接口的詳細(xì)步驟,在Node.js中接口可以采用多種形式,包括函數(shù)接口、對(duì)象接口和事件接口等,需要的朋友可以參考下
    2023-10-10

最新評(píng)論