前端踩坑记录
A 前端域的踩坑与排查。每条固定四段:症状 → 原因 → 解法 → 预防。 系统学习见 前端沉淀 与 A16 · CI 与 CD 与部署运维。
刷新页面 404:history 路由没配回退
症状
访问 https://site.com/about 刷新后报 404(或 Nginx 默认欢迎页),
但首页 / 能打开、站内跳转也正常。原因 前端用了 createWebHistory(history 模式),路由是浏览器端的虚拟路径,服务器上没有 /about 这个真实文件。Nginx 找不到文件就按默认规则返回 404。
解法
server {
root /usr/share/nginx/html;
index index.html;
# history 模式核心:所有找不到的路径都回退到 index.html
location / {
try_files $uri $uri/ /index.html;
}
}预防 上生产前先验证"深层路由 + 刷新"场景;改用 createWebHashHistory(#/about)可绕开,但不美观且不利于 SEO。
静态资源 404:Vite 的 base 没配子路径
症状
部署到 https://site.com/doc/ 后,页面能打开但 JS/CSS/图片全部 404。
Network 里看到请求的是 /assets/xxx.js 而不是 /doc/assets/xxx.js。原因 Vite 默认 base: '/',产出的资源链接写死为根路径。部署在子路径时路径全错。
解法
// vite.config.ts
export default defineConfig({
base: process.env.VITE_BASE || '/', // 部署到子路径时传 VITE_BASE=/doc/
})预防 把"子路径部署"当成默认能力,构建时通过环境变量注入 base,并在 CI 里显式传值。
构建失败:本机能过、CI 报错
症状
本地 npm install && npm run build 正常,CI 里同样命令失败:
lock file version mismatch / peer dependency 冲突 / 模块找不到。原因 大概率是依赖不一致:本地用了 npm install(可能升了版本、改了 lock),CI 用的是锁文件;或 Node 版本不同导致原生模块(node-sass、esbuild)行为不一致。
解法
# CI 一律用 npm ci(严格按 lock 安装,不碰版本)
npm ci && npm run build
# 明确 Node 版本
# .nvmrc 或 CI 配置:setup-node 里 node-version 与本地保持一致预防 提交 lock 文件;CI 与本地固定同一 Node 主版本;升级依赖单独提交并让 CI 先跑一遍。
跨域请求被拦截:CORS
症状
浏览器 Console:
Access to fetch at 'https://api.example.com' from origin
'http://localhost:5173' has been blocked by CORS policy.原因 浏览器同源策略:前端页面源(协议+域名+端口)与接口源不一致,服务端没有返回允许该源的 CORS 头。
解法
# FastAPI 示例:开发期放行
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:5173"], # 生产换成真实域名,别用 *
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)预防 分清"CORS 是服务端该配的头",不是前端能绕过的;生产不要 allow_origins=["*"] 且同时 allow_credentials=True(浏览器会拒绝)。
Cookie 没带过去 / SameSite 拦截
症状
前端域名 a.com,接口域名 api.example.com。fetch 带 credentials 但 Cookie 始终没发出去,
或 Set-Cookie 没被保存。原因 跨站/跨域场景下 Cookie 的 SameSite、Domain、Secure 三项决定是否发送与保存。SameSite=Lax 默认在跨站请求不携带;Secure 要求 HTTPS;Domain 不匹配不生效。
解法
方案一:前后端同源(最省事)——接口也走 a.com/api,用路径区分。
方案二:跨域则配置:
- 前端 fetch 加 credentials: 'include'
- 服务端 Set-Cookie: SameSite=None; Secure(必须 HTTPS)
- Cookie 的 Domain 设为公共父域(如 .example.com)预防 先确认"到底是谁的 Cookie 没发"——是没 Set 成功、Domain 不匹配、还是 SameSite 拦截,分别查。
线上更新看不到:浏览器缓存
症状
新版本已部署,但用户(尤其老用户)打开还是旧页面;自己强制刷新才看到新版。原因index.html 被缓存,或静态资源文件名没带 hash。Vite 默认对 JS/CSS 加 hash(assets/index-abc123.js),但 index.html 若被 CDN/浏览器缓存且缓存策略过长,用户拿不到新的入口文件。
解法
# index.html 短缓存 / 不缓存
location = /index.html {
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
# 带 hash 的静态资源长缓存
location /assets/ {
add_header Cache-Control "public, max-age=31536000, immutable";
}预防 静态资源走"文件名 hash + 长缓存",index.html 走"不缓存";发布后用无痕窗口或带版本号的 URL 验证。
移动端高度塌陷 / 溢出:100vh
症状
移动端(尤其 iOS Safari)底部被浏览器工具栏遮挡,或 100vh 元素内容被裁掉;
滚动时地址栏收起,高度跳动。原因100vh 在移动浏览器里等于"可视区最大高度",但地址栏收起/展开时视口高度会变,vh 单位不跟随。
解法
/* 方案一:用动态视口单位 */
height: 100dvh;
/* 方案二:撑满的容器用 min-height + 不写死高度 */
min-height: 100vh;预防 整页布局避免写死 100vh,用 min-height + flex 或 dvh;底部固定栏用 env(safe-area-inset-bottom) 适配刘海/底部条。
依赖装不上:npm 锁文件漂移
症状
package-lock.json 显示 modified,或新同事 npm install 后版本不一致、出现
`npm error code ERESOLVE`。原因npm install 会按语义版本更新并改写 lock;多人各跑一次就产生漂移。ERESOLVE 常见于 peerDependencies 冲突(如 React 18/19 混装)。
解法
# 恢复一致性
git checkout -- package-lock.json # 丢弃本地 lock 改动(确认无新增依赖)
npm ci # 严格按 lock 安装
# 真需要升依赖时:单独 npm install <pkg>@<version> 并提交 lock预防 团队统一用 npm ci;lock 文件提交且视为"唯一真相";升级依赖单独提交、CI 验证后再合。