Umi 开发代理(proxy)配置完全指南:从跨域原理到源码实现
【免费下载链接】umiA framework in react community ✨项目地址: https://gitcode.com/GitHub_Trending/um/umi
在 Umi 项目中,
proxy配置用于在开发(dev)阶段将特定前缀的网络请求转发到远程目标服务器,从而优雅解决浏览器同源策略带来的跨域问题。本文以 docs/docs/docs/guides/proxy.md 官方指南为核心骨架,结合仓库内 bundler-utils、bundler-webpack、bundler-vite 等包的源码实现,系统讲解代理的工作机制、完整配置语法、进阶参数以及生产环境的替代方案。读完本文,你将能独立为 Umi 应用配置开发代理、理解其底层调用链,并在生产环境遇到跨域时知道如何迁移到 Nginx。
什么是代理,为什么开发时需要它
代理(Proxy)是一种特殊的网络服务,它允许一个终端(一般为客户端)通过这个服务与另一个终端(一般为服务器)进行非直接的连接。在 Umi 的项目开发(dev)阶段,本地会启动一个 Node server,所有网络请求(包括资源请求)都会先经过这个本地 server 做响应分发。Umi 正是利用这一点,通过 http-proxy-middleware 中间件,将匹配规则的请求转发到另一个目标服务器上。
一个典型的场景是:前端代码里执行fetch('/api'),实际要取回的是远程http://jsonplaceholder.typicode.com/的数据。借助代理,无需修改业务代码,即可让/api开头的请求在本地被"接力"到远程接口。
从仓库源码看,这一机制在两类底层打包器中均有落点:
- Webpack 场景:packages/bundler-webpack/src/server/server.ts 中读取
userConfig.proxy并调用createProxy(proxy, app); - Vite 场景:packages/bundler-vite/src/server/server.ts 同样在 dev server 初始化时执行
createProxy(userConfig.proxy, app)。
两者最终都会汇聚到 packages/bundler-utils/src/proxy.ts 中的createProxy函数,通过内置(compiled)的http-proxy-middleware将代理注册到 Express 应用上。也就是说,无论使用哪套构建链路,proxy配置的语义是一致的。
基础用法:一行配置打通远程接口
在 Umi 中实现上述需求,只需要在配置文件(如.umirc.ts或config/config.ts)中加入proxy配置:
export default { proxy: { '/api': { 'target': 'http://jsonplaceholder.typicode.com/', 'changeOrigin': true, 'pathRewrite': { '^/api' : '' }, }, }, }这段配置的含义是:
/api(键名):匹配规则,凡是以/api开头的请求都会被该条代理规则捕获;target:目标服务器地址,请求最终会被转发到这里;changeOrigin:将请求头中的Host/Origin修改为目标服务器的地址,避免部分后端校验来源导致拒绝;pathRewrite:在转发前重写请求路径,例如把/api前缀替换为空字符串。
因此,当你请求/api/a时,实际请求的是http://jsonplaceholder.typicode.com/a。
注意:请求代理代理的是"请求所指向的服务",而不会直接修改浏览器中发起的请求 URL。本地 server 只是把目标服务器返回的数据原样传递回前端,所以你在浏览器 Network 面板看到的请求地址依然是
http://localhost:8000/api/a,只不过网络栈底层已经发生了转发。
底层的三种配置形态
从 packages/bundler-utils/src/proxy.ts 的源码可以看出,createProxy实际兼容了三种书写形态:
// 形态一:对象键值对,键即匹配 context proxy: { '/api': { target: '...', context: '...' } } // 形态二:单条配置,省略 context 时以 target 判定为单条 proxy: { target: 'http://...', changeOrigin: true } // 形态三:数组形式,可配置多条 proxy: [ { context: '/api', target: 'http://...' }, { context: '/api2', target: 'http://...' }, ]源码的处理逻辑是:当配置为数组时直接展开;当配置对象含有target属性时视为单条代理;否则按键名(如/api)逐一取出,并把键名作为context传入createProxyMiddleware。因此最常用、最直观的还是第一种"前缀对象"写法。
用代理解决开发期的跨域访问问题
浏览器(或 WebView)存在同源策略(Same-Origin Policy):不同协议、域名、端口的资源访问会被拦截。在引入本地 Node 服务之前,解决跨域通常需要服务端配合设置 CORS(Cross-Origin Resource Sharing)响应头,例如你可能会遇到如下报错:
XMLHttpRequest cannot load https://api.example.com. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access.而代理方案的原理非常简单直白:
- 浏览器有跨域限制,但服务器之间没有跨域限制;
- 前端请求同源的本地服务(
http://localhost:8000); - 本地 Node server 收到请求后,代为请求非同源的远程服务;
- 把远程服务的响应数据原样回传,前端拿到数据,全程不触碰同源策略。
这样业务代码、请求 URL 都不用改动,跨域问题在开发期被"隐形"解决。
进阶:bypass 与更多参数说明
除了文档中演示的target、changeOrigin、pathRewrite,Umi 的代理配置还透传了 http-proxy-middleware 的能力,并额外封装了bypass。相关类型定义位于 packages/bundler-utils/src/types.ts:
export interface ProxyOptions extends HPMOptions { target?: string; context?: string | string[]; bypass?: ( ...args: [HPMFnArgs[1], HPMFnArgs[2], HPMFnArgs[3]] ) => string | boolean | null | void; }bypass允许你在请求进入代理前做条件判断,返回不同的结果会走不同的分支(见 proxy.ts):
- 返回字符串 URL:把
req.url改写为该地址后直接走本地 next 处理(bypass 到指定地址); - 返回
false:直接以 404 结束响应(res.end(404)); - 返回
null/undefined:正常进入代理中间件转发; - 返回其他值:跳过当前代理,交给后续中间件处理。
典型用途:某些接口需要直连本地 mock 而不是转发到远程时,用bypass做条件放行。
此外,从 proxy.ts 的封装实现还可以看到两个内置增强:
onProxyReq:当配置了changeOrigin时,会把请求头里的origin显式改写为目标服务的origin,避免部分后端对 Origin 做白名单校验时误伤;onProxyRes:在响应头中附加x-real-url,记录该响应实际对应的真实目标地址,便于调试时确认请求到底打到了哪里。
这些细节意味着你在 Umi 中使用代理时,不仅可以获得 http-proxy-middleware 的完整能力(如secure、ws、headers、timeout等透传参数),还能直接使用bypass做精细化路由控制。
重要边界:dev 与 build 的差异
proxy配置只作用于开发(dev)阶段,不作用于生产构建(build)产物。这是使用代理时必须牢记的边界:
- dev 阶段:本地 Node server 存活,代理中间件随 server 一起注册生效;
- build 阶段:产物是纯静态文件,没有 Node 代理层,
proxy配置不会参与构建结果。
因此,如果生产环境(build 后部署)出现跨域问题,合理的做法是同源部署,或将类似proxy的转发规则迁移到部署层的 Nginx 容器上,例如:
# Nginx 容器内的典型配置(示意,供生产迁移参考) location /api/ { proxy_pass http://jsonplaceholder.typicode.com/; proxy_set_header Host $host; }这样前端请求依然保持同源,跨域问题在接入层被消化,与 dev 期代理的"接力"思路一脉相承。
小结
Umi 的proxy配置以 http-proxy-middleware 为基础,在 dev server 上实现了"浏览器 → 本地 Node server → 远程目标"的转发链路,是解决开发期跨域问题最轻量、最常用的手段。其核心要点可归纳为:
| 要点 | 说明 |
|---|---|
| 配置位置 | 配置文件(.umirc.ts或config/config.ts)中的proxy字段 |
| 匹配方式 | 对象键名作为 context,支持字符串前缀与数组多规则 |
| 常用参数 | target、changeOrigin、pathRewrite |
| 进阶能力 | bypass条件放行、http-proxy-middleware 全量参数透传 |
| 生效范围 | 仅 dev 阶段;生产建议同源部署或迁移至 Nginx |
| 源码落点 | packages/bundler-utils/src/proxy.ts,由 bundler-webpack 与 bundler-vite 的 dev server 调用 |
掌握了这套配置与原理,你便能在日常开发中快速打通前后端联调,遇到疑难请求时也能借助bypass与x-real-url定位问题。
【免费下载链接】umiA framework in react community ✨项目地址: https://gitcode.com/GitHub_Trending/um/umi
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考