UniApp H5开发实战:proxy代理配置详解与跨域问题一站式解决
1. 为什么H5开发总会遇到跨域问题?
第一次用UniApp开发H5页面时,我对着浏览器控制台鲜红的跨域报错一脸懵。明明在小程序端运行正常的接口请求,到了H5就突然罢工。后来才发现这是浏览器特有的安全机制在作祟——就像小区门禁系统,不允许你拿着A栋的门禁卡刷开B栋的大门。
跨域的本质是浏览器对JavaScript的安全限制,当协议(http/https)、域名或端口任一不同时就会触发。比如你的前端页面在http://localhost:8080,而接口在https://api.example.com,这就构成了典型的跨域场景。有趣的是,这种限制只存在于浏览器环境,这也是为什么同样的代码在App和小程序端能正常运行。
在实际项目中,我遇到过最棘手的两种情况:一是调试时本地开发服务器访问测试环境接口,二是生产环境前端部署在CDN而接口在独立域名。有次紧急上线时,后端同学突然说服务器暂时无法配置CORS,当时急得我差点把咖啡洒在键盘上——幸好proxy代理救场。
2. manifest.json配置代理的完整指南
2.1 基础配置三步走
打开项目根目录的manifest.json文件,切换到"源码视图",找到或添加h5节点。这是我常用的配置模板:
"h5": {
"devServer": {
"https": false,
"port": 8080,
"disableHostCheck": true,
"proxy": {
"/api": {
"target": "https://your-api-domain.com",
"changeOrigin": true,
"secure": false,
"pathRewrite": {
"^/api": "/v1"
}
}
}
}
}
几个关键参数值得注意:
- disableHostCheck:关闭主机检查,解决Invalid Host header报错
- changeOrigin:修改请求头中的Origin为目标地址,这个不开启可能导致某些服务器拒绝请求
- pathRewrite:我习惯用它将通用前缀/api映射到具体的接口版本/v1
2.2 多环境智能配置技巧
实际开发中我们需要区分测试/生产环境。我的方案是通过环境变量动态配置:
"proxy": {
"/api": {
"target": process.env.API_BASE || "https://default-api.com",
"pathRewrite": {
"^/api": process.env.API_PREFIX || ""
}
}
}
然后在package.json中配置脚本命令:
"scripts": {
"dev:test": "cross-env API_BASE=https://test-api.com API_PREFIX=/test vite",
"dev:prod": "cross-env API_BASE=https://prod-api.com vite"
}
3. vue.config.js的代理配置方案
3.1 与manifest.json的差异
当项目需要更复杂的代理规则时,vue.config.js会更灵活。有次项目需要同时对接三个不同域名的微服务,我是这样配置的:
module.exports = {
devServer: {
proxy: {
'/user': {
target: 'https://user-service.com',
pathRewrite: { '^/user': '' },
headers: {
'X-Forwarded-Host': 'localhost:8080'
}
},
'/order': {
target: 'https://order-service.com',
auth: 'username:password'
},
'/api': {
target: 'https://main-api.com',
bypass: (req) => req.url.includes('.json') ? req.url : null
}
}
}
}
注意两个配置文件的优先级规则:
- 当两者同时存在时,manifest.json的配置会覆盖vue.config.js
- 修改vue.config.js需要重启服务,而manifest.json的修改有时热更新会生效
3.2 高级配置实战
对于需要Cookie的场景,必须配置withCredentials:
proxy: {
'/auth': {
target: 'https://auth.example.com',
secure: false,
changeOrigin: true,
onProxyReq: (proxyReq) => {
proxyReq.setHeader('X-Proxy', 'uniapp-h5')
},
cookieDomainRewrite: {
"*": "localhost"
}
}
}
4. 调试技巧与常见坑点
4.1 代理不生效的排查流程
- 检查配置加载:在终端运行
npx vite inspect查看最终生效的配置 - 查看网络请求:Chrome开发者工具中确认请求URL是否被正确重写
- 服务端验证:用Postman直接请求代理目标地址,排除服务端问题
- 日志输出:添加proxy事件监听
devServer: {
proxy: {
'/api': {
target: 'https://api.example.com',
onProxyReq: (proxyReq, req, res) => {
console.log(`Proxying: ${req.url} => ${proxyReq.path}`)
}
}
}
}
4.2 那些年我踩过的坑
- 路径重写陷阱:有一次配置
pathRewrite: {'^/api': '/api/v1'}导致无限循环,最终改成{'^/api': '/v1'}才解决 - HTTPS证书问题:当目标服务器使用自签名证书时,需要设置
secure: false - WebSocket代理:需要单独配置ws: true,否则实时通信功能会失败
- 本地开发跨域:有时需要配合修改hosts文件,将域名指向127.0.0.1
5. 生产环境部署方案
虽然proxy在开发时很好用,但生产环境需要不同的策略。我的经验是:
- Nginx反向代理:最稳定的方案
location /api/ {
proxy_pass https://api-backend.com/;
proxy_set_header X-Real-IP $remote_addr;
proxy_redirect off;
}
- 云服务商解决方案:
- AWS的CloudFront + API Gateway
- 阿里云的CDN + 函数计算
- 腾讯云的API网关
- 纯前端方案:当完全没有后端支持时,可以考虑:
- 使用云函数做代理层
- JSONP(仅限GET请求)
- 现代浏览器支持的CORS配置
6. 接口请求的最佳实践
配置好代理只是第一步,实际项目中还需要考虑:
动态环境切换:
// config.js
export const API_BASE = import.meta.env.PROD
? '/api'
: '/proxy-api'
// request.js
uni.request({
url: `${API_BASE}/user/profile`,
// ...
})
错误处理增强:
uni.addInterceptor('request', {
fail: (err) => {
if(err.errMsg.includes('failed')) {
uni.showToast({ title: '网络异常', icon: 'none' })
}
return Promise.reject(err)
}
})
性能优化技巧:
- 对静态数据开启本地缓存
- 合并高频小请求
- 使用AbortController取消重复请求
7. 从原理理解代理工作机制
当你在浏览器中输入/api/user时,背后发生了这些事:
- 请求首先被开发服务器拦截(如Vite的connect中间件)
- 根据匹配规则找到对应的proxy配置
- 创建到目标服务器的HTTP连接
- 重写请求头(Host、Origin等)
- 转发请求并接收响应
- 将响应返回给浏览器
这个过程就像有个翻译官在中间协调两方的沟通。理解这个机制后,调试代理问题就会更有方向性。比如出现404时可以确定是路径重写问题,出现403通常是header配置问题。
8. 现代前端工具的代理差异
不同构建工具的代理配置有些微差异:
Vite项目:
// vite.config.js
export default {
server: {
proxy: {
'/api': {
target: 'http://jsonplaceholder.typicode.com',
rewrite: path => path.replace(/^\/api/, '')
}
}
}
}
Webpack项目:
// vue.config.js
module.exports = {
devServer: {
proxy: {
'/api': {
target: process.env.VUE_APP_API_URL,
agent: new https.Agent()
}
}
}
}
主要区别在于:
- Vite使用rewrite而非pathRewrite
- Webpack需要自行处理HTTPS agent
- Vite的配置更简洁,Webpack的可定制性更强
9. 安全防护要点
使用代理时要注意这些安全实践:
- 敏感信息过滤:配置onProxyRes钩子移除敏感响应头
onProxyRes: (proxyRes) => {
delete proxyRes.headers['x-server-version']
}
- 访问控制:限制代理路径的白名单
bypass: (req) => {
if(!req.url.includes('/valid-path')) {
return '/404'
}
}
- 日志审计:记录关键操作的代理日志
onProxyReq: (proxyReq, req) => {
auditLog(`Proxied: ${req.method} ${req.url}`)
}
10. 终极调试方案
当所有配置都检查过还是不行时,我的终极排错流程:
- 在终端运行
curl -v http://localhost:端口/api/test查看原始响应 - 使用whistle或Fiddler抓包分析网络流量
- 在Node层直接写最简单的HTTP代理服务器测试:
const http = require('http')
http.createServer((clientReq, clientRes) => {
const proxy = http.request({
host: 'target.com',
path: clientReq.url
}, (serverRes) => {
serverRes.pipe(clientRes)
})
clientReq.pipe(proxy)
}).listen(3000)
这种从最底层开始排查的方法,曾帮我解决过一个困扰团队三天的诡异跨域问题——原来是某个中间件偷偷修改了请求头。
更多推荐
所有评论(0)