H5本地开发CORS错误需通过devServer.proxy代理解决:webpack模式配置vue.config.js的devServer.proxy,Vite模式配置vite.config.ts的server.proxy,确保请求路径与代理规则严格匹配,且上线时依赖后端CORS配合。

uni-app H5本地开发时请求被浏览器拦截,提示 CORS 错误
这是最常见现象:H5端运行在浏览器中,uni.request 发出的请求实际走的是原生 XMLHttpRequest 或 fetch,受同源策略限制。而本地开发时,H5页面地址是 http://localhost:8080(或类似),后端接口却是 http://api.example.com,浏览器直接拒绝发送请求——不是 uni-app 的锅,是浏览器行为。
解决思路只有一条:让开发环境下的请求“看起来”是同源的。不能靠改后端响应头(本地调试时你未必能改生产接口),也不能靠禁用浏览器安全策略(不现实)。
- 必须启用
vue.config.js中的devServer.proxy配置,把接口请求代理到本地开发服务器,再由它转发给真实后端 - 代理路径需和你代码中写的
url保持一致,比如代码里调/api/user,那 proxy 就得配/api开头的路径 - 注意 uni-app 的 H5 构建默认使用 webpack-dev-server,所以
devServer配置有效;但如果你用了 Vite 模式(uni-app@3.9++vite),就得改vite.config.ts里的server.proxy
uni-app H5 devServer.proxy 配置写法和常见错误
很多人照抄网上示例却无效,核心问题在于路径匹配规则没对上,或者没意识到 uni-app 的 H5 请求默认不带 /api 前缀。
- 如果后端接口是
https://api.example.com/v1/login,建议统一在代码里写成相对路径:uni.request({ url: '/api/v1/login' }),然后 proxy 配置/api前缀 -
vue.config.js中正确写法(webpack 模式):module.exports = { devServer: { proxy: { '/api': { target: 'https://api.example.com', changeOrigin: true, pathRewrite: { '^/api': '/v1' } // 把 /api/v1/login → /v1/login } } } } - 容易踩的坑:
changeOrigin: true必须设为true,否则 Host 头不会改成目标域名,有些后端会校验 Host 导致 403;pathRewrite的正则必须用字符串字面量('^/api'),不能写成/^\/api/这种正则字面量(webpack 5+ 不认) - Vite 模式下,
vite.config.ts写法略有不同,server.proxy接收对象而非函数,且rewrite是函数:server: { proxy: { '/api': { target: 'https://api.example.com', changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, '/v1') } } }为什么 uni-app 的条件编译不能绕过跨域
有人试过这样写:
#ifdef H5里用fetch加mode: 'no-cors',结果发现状态码永远是 0、响应体读不到——因为no-cors只允许发简单请求(GET/POST + 简单 header),且返回内容被浏览器屏蔽,根本没法用。-
uni.request在 H5 平台底层就是封装的fetch或XHR,它不提供绕过 CORS 的能力,也不该提供 - 条件编译只能控制「发什么请求」,不能改变浏览器的安全模型。想在 H5 上拿到响应数据,就必须满足 CORS 规范,要么后端配
Access-Control-Allow-Origin,要么走代理 - 本地开发阶段,后端配 CORS 往往不可行(比如联调测试环境不允许改响应头),所以代理是唯一靠谱路径
H5 跨域问题在真机调试和上线时的表现差异
很多人本地跑通了就以为万事大吉,结果真机预览或上线后又报错,原因很直接:代理只在
npm run dev:h5本地服务下生效,一打包发布,代理就没了。- 打包后的 H5 是静态文件,直接由 Nginx/Apache 或 CDN 托管,没有 devServer,自然也没有 proxy。此时必须靠后端配置 CORS,或前端换用 JSONP(仅 GET)、服务端渲染中转等方案
- 真机调试(如微信开发者工具、手机扫码)走的仍是本地
http://localhost:8080,所以代理依然生效;但一旦生成正式包部署到域名下,就完全依赖线上环境的 CORS 策略 - 一个实用技巧:上线前,在
manifest.json里配置"h5": { "domain": "https://your-domain.com" },并确保所有接口域名与之同源,或后端已开启对应域名的 CORS 白名单
-










