如何配置Nginx适配React/React Router?遇unexpected token <错误求助
unexpected token <错误 兄弟我太懂这个坑了!你碰到的unexpected token <错误,结合你说的main.chunk.js返回index.html的情况,百分百是Nginx的路由配置没处理好React Router的单页特性,同时和Express的代理规则冲突了——我之前踩过一模一样的坑,给你一步步拆解解决:
问题根源
当你用React Router的browserHistory模式时,所有前端路由请求(比如/app/profile)都会被Nginx当成静态资源请求;如果Nginx没配置正确的fallback规则,或者错误地把静态资源请求(比如/main.chunk.js)转发给了Express,Express就会返回index.html(因为你可能配置了*路由返回index.html),浏览器拿到HTML却当成JS解析,自然就会报unexpected token <错误。
解决方案
1. 修正Nginx配置,区分静态资源和API代理
核心是让Nginx直接处理前端静态资源,只把API请求转发给Express,同时正确处理React Router的fallback。
假设你的静态React应用部署在/var/www/static-react,React/Express应用的build产物在/var/www/react-express/build,Express监听5001端口,给你一个参考配置:
server { listen 80; server_name your_domain_or_ip; # 处理根路径的静态React应用 location / { root /var/www/static-react; # 先找对应文件,找不到返回index.html(处理React Router) try_files $uri $uri/ /index.html; } # 处理React/Express应用(假设访问路径是/app) location /app { # 让Nginx直接serve build后的静态资源 root /var/www/react-express/build; # 注意这里的fallback是/app/index.html,不是根路径的! try_files $uri $uri/ /app/index.html; # 嵌套配置:只把/app/api开头的请求转发给Express location ~ /app/api { proxy_pass http://localhost:5001; # 这些header配置保证Express能正确获取请求信息 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } # 如果你的Express API直接在根路径/api,单独配置这个 # location /api { # proxy_pass http://localhost:5001; # proxy_set_header Host $host; # proxy_set_header X-Real-IP $remote_addr; # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # proxy_set_header X-Forwarded-Proto $scheme; # } }
关键注意点:
try_files的最后一个参数一定要对应你的React应用部署路径,比如部署在/app下就写/app/index.html,绝对不能写根路径的/index.html,否则会加载错误的静态资源。- 一定要把API请求的路由单独拆分出来,避免静态资源请求被转发给Express。
2. 调整Express的路由顺序
确保Express先处理静态资源,再处理API路由,最后才是单页应用的fallback(如果需要)。你的index.js应该改成这样:
const express = require('express'); const path = require('path'); const app = express(); // 1. 优先serve React build后的静态文件 app.use(express.static(path.join(__dirname, 'build'))); // 2. 然后定义所有API路由 app.get('/api/hello', (req, res) => { res.json({ message: 'Hello from Express!' }); }); // 3. 最后处理所有其他请求,返回index.html(仅当Express需要直接serve单页应用时) app.get('*', (req, res) => { res.sendFile(path.join(__dirname, 'build', 'index.html')); }); app.listen(5001, () => { console.log('Server running on port 5001 🚀'); });
为什么要这么做:如果Nginx把静态资源请求转发给Express,Express会先尝试返回对应的静态文件,而不是直接返回index.html——不过最好还是让Nginx直接处理静态资源,这样性能更好,也避免冲突。
3. 验证配置并重启服务
- 先检查Nginx配置是否合法:
sudo nginx -t - 如果提示
test is successful,重启Nginx:sudo systemctl restart nginx - 清除浏览器缓存(或者用隐私模式打开),避免之前缓存的错误HTML影响测试。
最后验证
现在通过Nginx访问你的React/Express应用,打开浏览器控制台,查看main.chunk.js的返回内容——应该是JS代码而不是index.html,unexpected token <错误也会消失,同时React Router的路由也能正常工作。
内容的提问来源于stack exchange,提问作者SrdjaNo1

