外观
uni-app 打包 H5 的跨域坑
页面能打开、标题也渲染出来了,但内容区一片空白,写着「连不上服务端」。第一反应是后端挂了,结果查了一圈发现后端好得很。
先排除后端
bash
systemctl status 你的服务 --no-pager
ss -lntp | grep 你的端口
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:端口/api/xxx三行都正常,说明后端没问题。那就是前端请求的地址不对。
头号元凶:接口地址被硬编码成 IP
用 IP 部署的那一版,打包产物里往往写死了 https://x.x.x.x:
js
const s = "https://1.2.3.4"; // 接口 baseURL
function request(path) { /* url: s + path */ }
function cover(url) { return s + url; } // 封面等相对资源也拼绝对地址于是从 https://example.cn 打开时,浏览器跑去请求 https://1.2.3.4/api/...——跨域。而接口通常不会返回 Access-Control-Allow-Origin,浏览器直接把响应丢掉,前端只能拿到一个笼统的 request:fail。
怎么定位
扫全部打包产物,别只看主 chunk:
bash
cd dist/assets
for f in *.js; do
r=$(grep -oE "(https?://[a-zA-Z0-9._:/-]+|/api/[a-zA-Z0-9_/-]*)" "$f" | sort -u | tr '\n' ' ')
[ -n "$r" ] && echo "[$f] $r"
done两种修法
改前端,用相对路径(推荐)
把 baseURL 改成空串,请求就变成同域的 /api/...,跨域问题直接消失:
js
const baseUrl = '' // 原来是 'https://1.2.3.4'小程序端需要完整域名,用条件编译分开:
js
// #ifdef H5
const baseUrl = ''
// #endif
// #ifndef H5
const baseUrl = 'https://example.cn'
// #endif后端加 CORS 头(前端不好改时)
nginx
location ~ ^/(api|img|cover|admin)(/|$) {
add_header Access-Control-Allow-Origin "https://example.cn" always;
proxy_pass http://127.0.0.1:3100;
# ...
}别图省事写 *
Access-Control-Allow-Origin: * 会让任何网站都能读你的接口。精确到具体的源。
应急:直接改打包产物
服务器上没有前端源码、又急着恢复时,可以直接改产物:
bash
cd /path/to/dist/assets
cp -a x.js "x.js.bak-$(date +%Y%m%d-%H%M%S)" # 先备份
sed -i "s|https://1.2.3.4||" x.js # 保持文件名不变两个必须注意的点
一、文件名不能改。 打包产物之间靠 import "./x.js" 互相引用,改名会直接断链。
二、改完必须处理缓存。 文件名没变、内容变了,而原响应又没有 Cache-Control,浏览器会走启发式强缓存(约 Last-Modified 时长的 10%,可能长达一两天)——用户怎么刷新都拿不到新版。
nginx
location /assets/ {
add_header Cache-Control "no-cache" always;
}add_header 会被 try_files 吞掉
在同一 location 里写 try_files 时,add_header 可能完全不生效——try_files 命中文件时的内部重定向会把响应头处理链绕过去。实测加上 try_files $uri =404; 后,响应里根本看不到 cache-control。
去掉 try_files 即可。验证:
bash
curl -s -D - -o /dev/null https://example.cn/assets/x.js | grep -i cache-control验证静态资源要看对配置
服务器上常常有多份 nginx 配置:一份 default_server 管 IP 访问,一份带 server_name 管域名。用 IP 去测资源会落到前者,测不到你改的那份。
用域名 + --resolve 指向源站才准:
bash
curl -s -D - -o /dev/null --resolve example.cn:443:127.0.0.1 https://example.cn/assets/x.js最后别忘了小程序
小程序调用 https://example.cn 还要在微信公众平台 → 开发管理 → 服务器域名里把域名加进 request 合法域名。这一项不在代码里,漏了照样报错。