首頁 web前端 js教程 透過Koa2框架利用CORS實現跨域ajax請求的方法

透過Koa2框架利用CORS實現跨域ajax請求的方法

Jun 01, 2018 am 11:17 AM
cors koa2 使用

這篇文章主要介紹了淺談Koa2框架利用CORS完成跨域ajax請求,現在分享給大家,也給大家做個參考。

實現跨域ajax請求的方式有很多,其中一個是利用CORS,而這個方法關鍵是在伺服器端進行設定。

本文僅對能夠完成正常跨域ajax回應的,最基本的配置進行說明(深層的配置我也不會)。

CORS將請求分為簡單請求和非簡單請求,可以簡單的認為,簡單請求就是沒有加上額外請求頭部的get和post請求,並且如果是post請求,請求格式不能是application /json(因為我對這一塊理解不深如果錯誤希望能有人指出錯誤並提出修改意見)。而其餘的,put、post請求,Content-Type為application/json的請求,以及自訂的請求頭部的請求,就為非簡單請求。

簡單請求的配置十分簡單,如果只是完成回應就達到目的的話,只需配置回應頭部的Access-Control-Allow-Origin即可。

如果我們在http://localhost:3000 網域下想要造訪 http://127.0.0.1:3001 網域。可以做如下設定:

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

然後用ajax發起一個簡單請求,例如post請求,就可以輕鬆的得到伺服器正確回應了。

實驗程式碼如下:

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

伺服器端程式碼:

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

然後就能得到正確的回應訊息了。

這時候如果看一下請求和回應的頭部訊息,會發現請求頭部多了個origin(還有一個referer為發出請求的url位址),而回應頭部多了個Access- Control-Allow-Origin。

現在可以發送簡單請求了,但是要想傳送非簡單請求還是需要其他的設定。

當第一次發出非簡單請求的時候,實際上會發出兩個請求,第一次發出的是preflight request,這個請求的請求方法是OPTIONS,這個請求是否通過決定了這一個種類的非簡單請求是否能成功得到回應。

為了能在伺服器匹配到這個OPTIONS類型的請求,因此需要自己做一個中間件來進行匹配,並給出回應使得這個預檢能夠通過。

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

這樣OPTIONS請求就能夠通過了。

如果檢查一下preflight request的請求頭部,會發現多了兩個請求頭。

Access-Control-Request-Method: PUT
Origin: http://localhost:3000
登入後複製

要透過這兩個頭部資訊與伺服器進行協商,看是否符合伺服器應答條件。

很容易理解,既然請求頭多了兩個訊息,回應頭自然也應該有兩個訊息相對應,這兩個訊息如下:

Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Methods: PUT,DELETE,POST,GET
登入後複製
登入後複製

第一個訊息和origin相同因此通過。第二個訊息對應Access-Controll-Request-Method,如果在請求的方式包含在伺服器允許的回應方式之中,因此這條也通過。兩個約束條件都滿足了,所以可以成功的發起請求。

至此為止,相當於僅僅完成了預檢,還沒發送真正的請求。

真正的請求當然也成功獲得了回應,並且回應頭如下(省略不重要部分)

Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Methods: PUT,DELETE,POST,GET
登入後複製
登入後複製

請求頭如下:

Origin: http://localhost:3000
登入後複製

這就很顯而易見了,回應頭部資訊是我們在伺服器設定的,因此是這樣。

而客戶端因為剛才已經預先檢查過了,所以不需要再發Access-Control-Request-Method這個請求頭了。

這個範例的程式碼如下:

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

伺服器程式碼:

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();
});
登入後複製

至此我們完成了能夠正確進行跨網域ajax回應的基本配置,還有一些可以進一步配置的東西。

例如,到目前為止,每一次非簡單請求都會實際上發出兩次請求,一次預檢一次真正請求,這就比較損失性能了。為了能不發預檢請求,可以設定如下回應頭。

Access-Control-Max-Age: 86400
登入後複製

這個回應頭的意義在於,設定一個相對時間,在該非簡單請求在伺服器端通過檢驗的那一刻起,當流逝的時間的毫秒數不足Access-Control-Max-Age時,就不需要再進行預檢,可以直接發送一次請求。

當然,簡單請求時沒有預檢的,因此這條程式碼對簡單請求沒有意義。

目前程式碼如下:

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();
});
登入後複製

到現在為止,可以對跨網域ajax請求進行回應了,但是該網域下的cookie不會被攜帶在請求頭中。如果想要帶著cookie到伺服器,並且允許伺服器對cookie進一步設置,還需要進一步的配置。

為了方便後續的偵測,我們預先在http://127.0.0.1:3001這個網域下設定兩個cookie。注意不要錯誤把cookie設定成中文(剛才我就設定成了中文,結果報錯,半天沒找到出錯原因)

然後我們要做兩步,第一步設定回應頭Access-Control-Allow -Credentials為true,然後在客戶端設定xhr物件的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);
  });
登入後複製

服務端如下:

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();
});
登入後複製

这时就可以带着cookie到服务器了,并且服务器也可以对cookie进行改动。但是cookie仍是http://127.0.0.1:3001域名下的cookie,无论怎么操作都在该域名下,无法访问其他域名下的cookie。

现在为止CORS的基本功能已经都提到过了。

一开始我不知道怎么给Access-Control-Allow-Origin,后来经人提醒,发现可以写一个白名单数组,然后每次接到请求时判断origin是否在白名单数组中,然后动态的设置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();
});
登入後複製

这样就可以不用*通配符也可匹配多个origin了。

注意:ctx.origin与ctx.request.header.origin不同,ctx.origin是本服务器的域名,ctx.request.header.origin是发送请求的请求头部的origin,二者不要混淆。

最后,我们再稍微调整一下自定义的中间件的结构,防止每次请求都返回Access-Control-Allow-Methods以及Access-Control-Max-Age,这两个响应头其实是没有必要每次都返回的,只是第一次有预检的时候返回就可以了。

调整后顺序如下:

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();
});
登入後複製

这样就减少了多余的响应头。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

webpack打包js的方法

vue 简单自动补全的输入框的示例

angular5 httpclient的示例实战

以上是透過Koa2框架利用CORS實現跨域ajax請求的方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

如何利用GitLab進行專案文件管理 如何利用GitLab進行專案文件管理 Oct 20, 2023 am 10:40 AM

如何利用GitLab進行專案文件管理一、背景介紹在軟體開發過程中,專案文件是非常重要的資料,不僅能夠幫助開發團隊了解專案的需求和設計,還能提供給測試團隊和客戶參考。為了方便專案文件的版本控制和團隊協作,我們可以利用GitLab來進行專案文件管理。 GitLab是一個基於Git的版本控制系統,除了支援程式碼管理,還可以管理專案文件。二、GitLab環境建置首先,我

如何使用Flask-CORS實現跨域資源共享 如何使用Flask-CORS實現跨域資源共享 Aug 02, 2023 pm 02:03 PM

如何使用Flask-CORS實現跨域資源共享引言:在網路應用開發中,跨域資源共享(CrossOriginResourceSharing,簡稱CORS)是一種機制,允許伺服器與指定的來源或網域名稱之間共享資源。使用CORS,我們可以靈活地控制不同域之間的資料傳輸,實現安全、可靠的跨域存取。在本文中,我們將介紹如何使用Flask-CORS擴充庫來實現CORS功

抖音推薦影片是什麼意思?如何利用抖音推薦影片? 抖音推薦影片是什麼意思?如何利用抖音推薦影片? Mar 27, 2024 pm 03:01 PM

抖音作為一個全球知名的短視頻社交平台,靠著其獨特的個人化推薦演算法贏得了廣大用戶的青睞。本文將深入研究抖音影片推薦的價值和原理,幫助讀者更了解並充分利用這項功能。一、什麼是抖音推薦影片抖音推薦影片是根據用戶的興趣和行為習慣,利用智慧推薦演算法為用戶篩選和推送個人化影片內容。抖音平台透過分析用戶的觀看歷史、按讚和評論行為、分享記錄等數據,從龐大的影片庫中精選出最符合用戶口味的影片進行推薦。這種個人化推薦系統不僅提高了用戶體驗,也幫助用戶發現更多符合其喜好的影片內容,從而增強用戶黏性和留存率。在這個

如何在PHP-Slim框架中使用CORS跨域請求? 如何在PHP-Slim框架中使用CORS跨域請求? Jun 03, 2023 am 08:10 AM

在Web開發中,跨域請求是一個常見的問題。這是因為瀏覽器對於不同網域名稱之間的請求有嚴格的限制。例如,網站A的前端程式碼無法直接向網站B的API發送請求,除非網站B允許跨網域請求。為了解決這個問題,出現了CORS(跨域資源共享)技術。本文將介紹如何在PHP-Slim框架中使用CORS跨域請求。一、什麼是CORSCORS是一種機制,它透過在對應的HTTP頭中添加一些額

如何使用 Golang 建立 RESTful API 並實作 CORS? 如何使用 Golang 建立 RESTful API 並實作 CORS? Jun 02, 2024 pm 05:52 PM

建立RESTfulAPI並實作CORS:建立專案並安裝相依性。設定HTTP路由處理請求。使用middlewareCORS中間件啟用跨域資源共享(CORS)。將CORS中間件套用至路由器,允許來自任何網域的GET和OPTIONS請求。

在Beego框架中使用CORS解決跨域問題 在Beego框架中使用CORS解決跨域問題 Jun 04, 2023 pm 07:40 PM

隨著Web應用程式的發展和互聯網的全球化,越來越多的應用程式需要進行跨域請求。對於前端開發人員而言,跨域請求是一個常見的問題,它可能導致應用程式無法正常運作。在這種情況下,解決跨域請求問題的最佳方法之一是使用CORS。在本文中,我們將重點放在如何在Beego框架中使用CORS來解決跨域問題。什麼是跨域請求?在網路應用程式中,跨網域請求是指從一個網域的網頁向另一

如何利用 Go 語言進行並發程式設計? 如何利用 Go 語言進行並發程式設計? Jun 10, 2023 am 10:33 AM

隨著電腦硬體的不斷發展,處理器中的CPU核心不再單獨增加時脈頻率,而是增加核心數。這引發了一個顯而易見的問題:如何發揮這些核心的效能?一種解決方法是透過平行編程,即同時執行多個任務,以充分利用CPU核心。這就是Go語言的一個獨特之處,它是一門專為並發程式設計而設計的語言。在本文中,我們將探討如何利用Go語言進行並發程式設計。協程首先,我們需要了解

springboot解決CORS跨域的方式有哪些 springboot解決CORS跨域的方式有哪些 May 13, 2023 pm 04:55 PM

一、實作WebMvcConfigurer介面@ConfigurationpublicclassWebConfigimplementsWebMvcConfigurer{/***新增跨網域支援*/@OverridepublicvoidaddCorsMappings(CorsRegistryregistry){//允許跨網域存取的路徑'/**'表示應用程式的所有方法? ")//允許跨網域存取的來源'*

See all articles