戰(zhàn):基于 @koa/cors 中間件的 CORS 實(shí)現(xiàn)指南)
后端微服務(wù)云原生【免費(fèi)下載鏈接】midway A Node.js Serverless Framework for front-end/full-stack developers. Build the application for next decade. Works on AWS, Alibaba Cloud, Tencent Cloud and traditional VM/Container. Super easy integrate with React and Vue. 項(xiàng)目地址https://gitcode.com/gh_mirrors/mi/midway點(diǎn)擊查看免費(fèi)下載導(dǎo)讀在前后端分離的現(xiàn)代 Web 開發(fā)中瀏覽器同源策略導(dǎo)致的跨域CORS問(wèn)題幾乎是每個(gè)全棧開發(fā)者都要面對(duì)的第一道坎。本文聚焦 Midway Hooks 項(xiàng)目Node.js 全棧/前后端一體化框架的 Hooks 體系中如何通過(guò)koa/cors中間件配置跨域覆蓋從依賴安裝、全局中間件掛載到全部核心配置項(xiàng)逐一拆解的完整流程。讀完本文你將能夠在 Midway Hooks 項(xiàng)目中獨(dú)立完成跨域配置并理解origin、credentials、allowMethods等關(guān)鍵參數(shù)對(duì)瀏覽器預(yù)檢請(qǐng)求與響應(yīng)頭的影響。背景為什么 Midway Hooks 需要 CORS 配置Midway Hooks 是基于函數(shù)式編程風(fēng)格Functional API構(gòu)建 API 的開發(fā)模式開發(fā)者不再編寫傳統(tǒng) Controller而是通過(guò)Api()、Get()等函數(shù)式裝飾器定義接口配合useContext()訪問(wèn)請(qǐng)求上下文。由于這種模式天然面向前后端一體化場(chǎng)景前端頁(yè)面與后端接口經(jīng)常運(yùn)行在不同的端口甚至不同域名上瀏覽器便會(huì)基于同源策略攔截跨源請(qǐng)求。從倉(cāng)庫(kù)中的示例項(xiàng)目 samples/functional-api-service 可以看出Hooks 應(yīng)用的入口是 src/configuration.ts其中通過(guò)imports注冊(cè)midwayjs/koa等框架組件。這正是 CORS 中間件需要掛載的位置——在 Hooks 體系中中間件統(tǒng)一通過(guò)hooks()配置對(duì)象的middleware數(shù)組注入koa/cors作為標(biāo)準(zhǔn) Koa 中間件可以無(wú)縫接入。使用方法第一步安裝依賴在項(xiàng)目根目錄執(zhí)行以下命令安裝koa/corsnpm install koa/corskoa/cors是 Koa 生態(tài)中最常用的 CORS 中間件基于koa的洋蔥模型實(shí)現(xiàn)專門用于向響應(yīng)報(bào)文寫入Access-Control-*系列跨域響應(yīng)頭。第二步在 configuration.ts 中啟用Hooks 應(yīng)用通過(guò)createConfiguration定義應(yīng)用配置imports中注冊(cè) Koa 框架與hooks()配置。將cors()中間件放入hooks()的middleware數(shù)組即可對(duì)全部接口啟用跨域import { createConfiguration, hooks, } from midwayjs/hooks; import * as Koa from midwayjs/koa; import cors from koa/cors; export default createConfiguration({ imports: [ Koa, hooks({ // 全局啟用 CORS允許任意來(lái)源訪問(wèn) middleware: [ cors({ origin: * }), ], }), ], });cors()返回的是一個(gè)標(biāo)準(zhǔn) Koa 中間件函數(shù)因此它同樣可以出現(xiàn)在 Midway Hooks 支持的任意中間件層級(jí)中。倉(cāng)庫(kù)文檔 site/docs/hooks/middleware.md 展示了中間件的三種掛載位置CORS 均可按需選擇全局中間件放在configuration.ts的hooks({ middleware: [...] })中對(duì)所有接口生效即上述示例文件級(jí)中間件在 API 文件中導(dǎo)出config: ApiConfig { middleware: [logger, cors] }對(duì)該文件內(nèi)所有 API 函數(shù)生效單函數(shù)中間件通過(guò)Middleware(logger, cors)包裹單個(gè)Api(Get(), ...)函數(shù)僅對(duì)該函數(shù)生效。其中「文件級(jí)」與「單函數(shù)級(jí)」兩種方式無(wú)需帶參數(shù)調(diào)用cors直接傳入函數(shù)本身即可例如middleware: [logger, cors]而全局方式通常顯式調(diào)用cors({ origin: * })以明確配置項(xiàng)。核心配置項(xiàng)詳解koa/cors支持的配置項(xiàng)如下這也是 Midway Hooks 中 CORS 能力的完整參數(shù)面/** * CORS middleware * * param {Object} [options] * - {String|Function(ctx)} origin Access-Control-Allow-Origin, default is request Origin header * - {String|Array} allowMethods Access-Control-Allow-Methods, default is GET,HEAD,PUT,POST,DELETE,PATCH * - {String|Array} exposeHeaders Access-Control-Expose-Headers * - {String|Array} allowHeaders Access-Control-Allow-Headers * - {String|Number} maxAge Access-Control-Max-Age in seconds * - {Boolean|Function(ctx)} credentials Access-Control-Allow-Credentials, default is false. * - {Boolean} keepHeadersOnError Add set headers to err.header if an error is thrown * return {Function} cors middleware * api public */逐項(xiàng)說(shuō)明如下配置項(xiàng)對(duì)應(yīng)響應(yīng)頭默認(rèn)值說(shuō)明originAccess-Control-Allow-Origin請(qǐng)求頭中的Origin允許的跨域來(lái)源可傳字符串如*或http://127.0.0.1:7001也可傳函數(shù)(ctx) string動(dòng)態(tài)返回。啟用credentials時(shí)不能使用*allowMethodsAccess-Control-Allow-MethodsGET,HEAD,PUT,POST,DELETE,PATCH允許的 HTTP 方法可傳字符串或字符串?dāng)?shù)組exposeHeadersAccess-Control-Expose-Headers無(wú)允許前端 JS 讀取的響應(yīng)頭列表默認(rèn)情況下瀏覽器只能讀取少量安全響應(yīng)頭allowHeadersAccess-Control-Allow-Headers請(qǐng)求頭中的Access-Control-Request-Headers允許的請(qǐng)求頭列表可傳字符串或字符串?dāng)?shù)組maxAgeAccess-Control-Max-Age無(wú)預(yù)檢請(qǐng)求Preflight結(jié)果可緩存的秒數(shù)減少瀏覽器重復(fù)發(fā)送 OPTIONS 請(qǐng)求credentialsAccess-Control-Allow-Credentialsfalse是否允許攜帶 Cookie 等憑證可傳布爾值或函數(shù)(ctx) booleankeepHeadersOnError無(wú)false中間件執(zhí)行報(bào)錯(cuò)時(shí)是否將已設(shè)置的跨域響應(yīng)頭寫入err.headers便于上層錯(cuò)誤處理時(shí)透?jìng)鱫rigin控制允許的來(lái)源origin是 CORS 配置中最核心的選項(xiàng)。默認(rèn)行為是回顯請(qǐng)求頭中的Origin值即允許任意來(lái)源。生產(chǎn)環(huán)境若要收緊應(yīng)顯式指定為具體域名例如cors({ origin: http://127.0.0.1:7001 })需要根據(jù)請(qǐng)求動(dòng)態(tài)判斷來(lái)源時(shí)可以傳入函數(shù)cors({ origin: (ctx) { // 依據(jù) ctx.request.header.origin 或業(yè)務(wù)邏輯返回允許的來(lái)源 return https://example.com; }, })注意根據(jù) CORS 規(guī)范Access-Control-Allow-Origin一旦設(shè)置為*瀏覽器要求Access-Control-Allow-Credentials必須為false反之只要啟用credentials: trueorigin就不能是通配符*必須給出明確的來(lái)源或函數(shù)動(dòng)態(tài)返回值否則瀏覽器會(huì)拒絕響應(yīng)。credentials允許攜帶 Cookie 與憑證跨域請(qǐng)求若需要攜帶 Cookie例如fetch(url, { credentials: include })或 XMLHttpRequest 的withCredentials true服務(wù)端必須開啟credentials: truecors({ origin: http://127.0.0.1:7001, credentials: true, })如前所述該配置與origin: *互斥。倉(cāng)庫(kù)文檔 site/docs/extensions/cross_domain.md 中關(guān)于通用跨域組件的配置示例同樣強(qiáng)調(diào)了這一點(diǎn)可互為印證。allowMethods 與 allowHeaders預(yù)檢請(qǐng)求的通行證當(dāng)瀏覽器發(fā)起帶自定義頭如Content-Type: application/json、Authorization的跨域請(qǐng)求時(shí)會(huì)先發(fā)送 OPTIONS 預(yù)檢請(qǐng)求Preflight。服務(wù)端通過(guò)Access-Control-Allow-Methods與Access-Control-Allow-Headers告知瀏覽器允許的方法與請(qǐng)求頭匹配時(shí)瀏覽器才會(huì)放行真實(shí)請(qǐng)求。allowMethods默認(rèn)覆蓋GET,HEAD,PUT,POST,DELETE,PATCH基本滿足 RESTful API 場(chǎng)景若接口使用了自定義方法如OPTIONS之外的擴(kuò)展可按需追加cors({ allowMethods: [GET, POST, PUT, DELETE, PATCH, OPTIONS], allowHeaders: [Content-Type, Authorization, X-Requested-With], })maxAge緩存預(yù)檢結(jié)果maxAge單位為秒用于指示瀏覽器緩存本次預(yù)檢響應(yīng)避免每個(gè)跨域請(qǐng)求都觸發(fā)一次額外的 OPTIONS 往返。高頻調(diào)用的接口建議設(shè)置較大值例如cors({ maxAge: 86400 })緩存一天。exposeHeaders 與 keepHeadersOnErrorexposeHeaders默認(rèn)情況下瀏覽器只向 JS 暴露Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma等安全響應(yīng)頭自定義響應(yīng)頭如分頁(yè)信息X-Total-Count需要通過(guò)該選項(xiàng)顯式聲明后才能被前端讀取keepHeadersOnError當(dāng)后續(xù)中間件或業(yè)務(wù)代碼拋出異常時(shí)是否保留已寫入的跨域頭。若你的應(yīng)用有統(tǒng)一的全局錯(cuò)誤處理中間件且希望錯(cuò)誤響應(yīng)仍攜帶 CORS 頭應(yīng)將其設(shè)為true否則錯(cuò)誤響應(yīng)可能因缺少 CORS 頭而被瀏覽器攔截前端只能看到晦澀的網(wǎng)絡(luò)錯(cuò)誤而非真實(shí)錯(cuò)誤信息。與通用跨域組件的差異倉(cāng)庫(kù)還提供了面向傳統(tǒng)框架midwayjs/faas、midwayjs/web、midwayjs/koa、midwayjs/express的通用跨域組件midwayjs/cross-domain它通過(guò)Configuration({ imports: [crossDomain] })引入并支持在 config.default.ts 中以配置項(xiàng)形式聲明cors與jsonp模式詳見 site/docs/extensions/cross_domain.md。而本文所述的 Hooks 方式與它的本質(zhì)區(qū)別在于Midway Hooks 的函數(shù)式配置體系中CORS 被當(dāng)作一個(gè)普通 Koa 中間件注入hooks({ middleware: [...] })配置即代碼無(wú)需額外的組件裝載與配置中心適合以函數(shù)式 API 為主的新項(xiàng)目若你的項(xiàng)目同時(shí)存在傳統(tǒng) Controller 與 Hooks 兩種編碼風(fēng)格也可以按需混用這兩種跨域方案。常見問(wèn)題排查當(dāng)發(fā)現(xiàn) CORS 配置不生效時(shí)可以對(duì)照倉(cāng)庫(kù)文檔 site/docs/extensions/cross_domain.md 中總結(jié)的排查順序逐項(xiàng)確認(rèn)確認(rèn)請(qǐng)求確實(shí)跨域同源策略只約束瀏覽器環(huán)境服務(wù)端調(diào)用Node.js 內(nèi)部請(qǐng)求、curl 等不受 CORS 限制不設(shè)置任何配置也能成功確認(rèn)請(qǐng)求發(fā)自瀏覽器只有瀏覽器XMLHttpRequest、Fetch API才會(huì)執(zhí)行同源策略檢查確認(rèn)請(qǐng)求帶有Origin頭同源請(qǐng)求或部分瀏覽器場(chǎng)景如地址欄直達(dá)不帶Origin頭CORS 中間件據(jù)此無(wú)法觸發(fā)響應(yīng)頭寫入檢查預(yù)檢請(qǐng)求OPTIONS是否被中間件正確處理確認(rèn)allowMethods/allowHeaders與實(shí)際請(qǐng)求匹配檢查credentials與origin的搭配credentials: true時(shí)origin不能為*否則瀏覽器會(huì)因響應(yīng)頭非法而攔截。典型的 CORS 報(bào)錯(cuò)形如Access to fetch at http://127.0.0.1:7002/ from origin http://127.0.0.1:7001 has been blocked by CORS policy: No Access-Control-Allow-Origin header is present on the requested resource.該報(bào)錯(cuò)意味著服務(wù)端響應(yīng)中缺少Access-Control-Allow-Origin頭優(yōu)先檢查中間件是否已掛載、請(qǐng)求是否真的帶了Origin頭、以及錯(cuò)誤響應(yīng)是否因keepHeadersOnError為false而丟失了跨域頭。小結(jié)在 Midway Hooks 中配置 CORS 只需三步安裝koa/cors、在configuration.ts的hooks({ middleware })中掛載cors()、按需設(shè)置origin、credentials、allowMethods等參數(shù)。這套方案完全復(fù)用 Koa 生態(tài)的中間件能力代碼量小、作用域可控全局/文件級(jí)/單函數(shù)級(jí)均可并天然適配 Hooks 函數(shù)式 API 的開發(fā)范式。合理設(shè)置maxAge與keepHeadersOnError還能顯著優(yōu)化跨域請(qǐng)求的性能與錯(cuò)誤排查體驗(yàn)。如需進(jìn)一步了解中間件的三種掛載層級(jí)與更多中間件用法可繼續(xù)閱讀倉(cāng)庫(kù)文檔 site/docs/hooks/middleware.md通用框架下的跨域組件含 JSONP則見 site/docs/extensions/cross_domain.md。贊分享后端微服務(wù)云原生【免費(fèi)下載鏈接】midway A Node.js Serverless Framework for front-end/full-stack developers. Build the application for next decade. Works on AWS, Alibaba Cloud, Tencent Cloud and traditional VM/Container. Super easy integrate with React and Vue. 項(xiàng)目地址https://gitcode.com/gh_mirrors/mi/midway點(diǎn)擊查看免費(fèi)下載相關(guān)推薦Midway 跨域組件cross-domain完全指南CORS 與 JSONP 配置實(shí)戰(zhàn)Midway 跨域組件cross domain完全指南CORS 與 JSONP 配置實(shí)戰(zhàn) 導(dǎo)讀 Midway 提供了開箱即用的通用跨域組件 midway后端微服務(wù)云原生Wasp 多域名 CORS 配置實(shí)戰(zhàn)基于全局中間件管理跨域訪問(wèn)Wasp 多域名 CORS 配置實(shí)戰(zhàn)基于全局中間件管理跨域訪問(wèn) 本篇指南講解如何在 Wasp 應(yīng)用中通過(guò)自定義全局中間件global middlewareWeb框架后端前端CLI開發(fā)工具OpenCloud 中的 CORS 中間件rs/cors 配置、實(shí)現(xiàn)原理與實(shí)戰(zhàn)指南OpenCloud 中的 CORS 中間件rs/cors 配置、實(shí)現(xiàn)原理與實(shí)戰(zhàn)指南 導(dǎo)讀 OpenCloud 作為一款提供文件管理、共享與協(xié)同能力的開源平臺(tái)后端微服務(wù)存儲(chǔ)認(rèn)證鑒權(quán)上一篇告別冗長(zhǎng)命令行Chronicle-Core系統(tǒng)屬性文件加載機(jī)制詳解與最佳實(shí)踐下一篇LeetCode-Go 如何運(yùn)行 gotest.sh 生成 Codecov 可識(shí)別的單一覆蓋率文件 coverage.txt創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考