本文目录导读:
“源码跨域资源适配逻辑”通常指在前端项目源码(或构建产物) 中,处理不同域名(或端口、协议)下资源(API、图片、字体、iframe、脚本等)请求时的配置与运行时逻辑。
这个适配逻辑的核心目标是:在开发和线上不同环境、不同域名部署时,保证前端代码能正确请求到后端资源,且不被浏览器同源策略拦截。
下面从开发时适配、构建时适配、运行时适配三个层面,以及常见的适配方案来拆解。
开发时适配(Dev Server)
在本地开发(localhost:3000)时,前端请求后端 API(api.example.com:8080)一定会产生跨域,适配逻辑通常包括:
-
Proxy 代理(最常用)
- 逻辑: 在 Webpack/Vite 的
devServer中配置 proxy。 - 原理: 浏览器请求
/api/user-> 开发服务器接收 -> 开发服务器转发到http://api.example.com:8080/api/user-> 返回结果给浏览器。 - 优势: 浏览器感觉是同源请求,无需服务端配置 CORS,开发体验最好。
// vite.config.js (Vite 配置) export default defineConfig({ server: { proxy: { '/api': { target: 'http://api.example.com:8080', changeOrigin: true, // 适配路径:是否重写 /api/user -> /user rewrite: (path) => path.replace(/^\/api/, '') } } } }) - 逻辑: 在 Webpack/Vite 的
-
本地 Mock 数据
- 逻辑: 不依赖真实后端,本地拦截请求返回假数据。
- 工具: Mock.js, MSW (Mock Service Worker)。
构建时适配(Build Config)
源码打包后部署到线上(www.myapp.com),请求生产 API(api.myapp.com)。
-
环境变量注入
- 逻辑: 源码中不写死 API 地址,而是通过环境变量(
.env文件)读取。 - 适配点: 构建时根据
NODE_ENV或自定义变量替换为对应的域名。
// .env.production VITE_API_BASE_URL = 'https://api.myapp.com' // .env.development VITE_API_BASE_URL = '/api' // 开发时用proxy // 源码中使用 const response = await fetch(`${import.meta.env.VITE_API_BASE_URL}/user`) - 逻辑: 源码中不写死 API 地址,而是通过环境变量(
-
构建路径适配 (PublicPath)
- 如果静态资源(JS/CSS/字体)部署在 CDN(
cdn.myapp.com),而 HTML 在www.myapp.com,需要设置publicPath为绝对路径(CDN 域名)或相对路径,这属于资源的跨域引用。
- 如果静态资源(JS/CSS/字体)部署在 CDN(
运行时适配(Runtime Logic)
这是“适配逻辑”中最核心的技术部分,指代码在浏览器中运行时如何处理跨域。
CORS(服务端配合)
- 逻辑: 浏览器发现跨域请求后,检查响应头,若服务端未返回允许的头部,则拦截。
- 适配方式: 前端无法独立解决,必须让后端添加响应头。
Access-Control-Allow-Origin: https://www.myapp.com(指定域名)Access-Control-Allow-Methods: GET, POST, PUTAccess-Control-Allow-Headers: Content-Type, AuthorizationAccess-Control-Allow-Credentials: true(如果需要带着 Cookie)
JSONP(GET 请求适配)
- 逻辑:
<script>标签不受同源策略限制,利用src请求带回调,服务端返回callback(data)。 - 适用场景: 旧系统适配、仅 GET 请求、无需 Cookie。
function jsonp(url, callbackName) { return new Promise((resolve, reject) => { window[callbackName] = (data) => resolve(data); const script = document.createElement('script'); script.src = `${url}?callback=${callbackName}`; document.body.appendChild(script); }); } // 请求 https://api.other.com/data jsonp('https://api.other.com/data', 'mycallback').then(data => ...)
WebSocket(无同源策略)
- 逻辑: WebSocket 协议不受同源策略限制。
- 适配: 直接连接即可。
new WebSocket('wss://api.other.com/ws')。
postMessage + iframe(跨域通信)
-
场景: 嵌入第三方页面(如地图、支付页面),需要与父页面通信。
-
逻辑: 父窗口
iframe.contentWindow.postMessage(data, targetOrigin),子窗口监听message事件。// 父窗口 (https://www.myapp.com) const iframe = document.getElementById('other-domain-iframe'); iframe.contentWindow.postMessage({ action: 'getUserInfo' }, 'https://www.other.com'); // 子窗口 (https://www.other.com) window.addEventListener('message', (event) => { if (event.origin === 'https://www.myapp.com') { // 适配:检查来源 event.source.postMessage({ result: 'some data' }, event.origin); } });
特殊资源适配逻辑
除了 API,源码中的其他静态资源也有跨域问题:
-
图片 / 字体(CORS 属性)
-
逻辑: 浏览器对
<img>或@font-face的跨域请求有特殊处理,特别是字体默认限制跨域。 -
适配:
- 在
<img>上添加crossorigin="anonymous"(用于 Canvas 绘图时)。 - 字体文件必须由服务器返回
Access-Control-Allow-Origin头部。
<img src="https://cdn.other.com/logo.png" crossorigin="anonymous" />
- 在
-
-
Script 标签(CDN 资源)
-
逻辑:
script默认不受同源策略限制,但无法捕获错误细节(如文件内部报错的行号)。 -
适配:
- 在
<script>上添加crossorigin属性(需要服务端配合返回 CORS 头)。 window.onerror才能捕获到详细错误信息。
<script src="https://cdn.other.com/sdk.js" crossorigin="anonymous"></script>
- 在
-
典型的“适配流程图”
假设你有一个 React/Vue 应用:
- 源码编写时: 所有请求基地址写入配置文件
config.js,读取VITE_API_BASE_URL。 - 本地开发 (npm run dev):
.env.development中VITE_API_BASE_URL = ''或/proxy-api。- Vite/Webpack 的 Proxy 将
/proxy-api转发到http://192.168.1.100:8080。 - 适配结果: 无跨域问题。
- 构建打包 (npm run build):
- 读取
.env.production中的VITE_API_BASE_URL = 'https://api.myapp.com'。 - 打包后的 JS 中写死
https://api.myapp.com。
- 读取
- 线上运行时:
- 浏览器
www.myapp.com的 JS 发起请求到https://api.myapp.com/user。 - 若后端 Nginx/Node 配置了 CORS: 返回
Access-Control-Allow-Origin: https://www.myapp.com,请求成功。 - 若后端未配置 CORS: 请求失败(浏览器拦截)。
- 浏览器
- 错误处理与降级(适配逻辑的最后一层):
- 源码中需有 try-catch 或 axios 拦截器,若检测到跨域错误(
network error),可尝试降级方案(如通过自己的 BFF 层转发,或使用 JSONP 探测备用接口)。
- 源码中需有 try-catch 或 axios 拦截器,若检测到跨域错误(
“源码跨域资源适配逻辑”不是一个单一函数,而是一套贯穿开发、构建、运行三个阶段的策略组合。
- 开发期:
Proxy适配(让你在 localhost 开发无感)。 - 构建期:
环境变量适配(让不同环境拿到不同的 API 域名)。 - 运行期:
CORS / JSONP / postMessage / WebSocket适配(浏览器与不同域资源的实际通信)。
标签: 跨域资源