启用HTTPS的Nginx反向代理部署CRA构建React站点JS报错问询
HTTPS场景下React静态资源加载报错的排查与修复
先把常见误区掰明白
你碰到的Uncaught SyntaxError: Unexpected token '<' ,和JSX解析半毛钱关系没有,完全犯不上给script标签加type='text/babel'。
create-react-app打出来的生产包,早就在构建阶段把所有JSX语法转成了浏览器能直接识别的原生JS,根本不需要浏览器端再做JSX解析- 这个报错的本质直白说就是:你让浏览器去拉取
.js文件,结果服务器给你返回了一段HTML(就是单页应用的index.html,开头那行<!DOCTYPE html>的第一个字符就是<),浏览器刚读第一个字符就触发语法错误报了提示。
真要加了type='text/babel'反而会出更大的问题:浏览器看到这个属性的script标签,默认根本不会自动执行里面的脚本,必须额外引入babel-standalone的库才能解析,而生产构建包里根本没这个依赖,最后直接页面全白,连之前的报错都看不到了。
顺着你的配置找根因
你的部署链路是:浏览器 → 主机上的外层Nginx(80/443端口,配置了Let's Encrypt证书) → 容器里的nginx-blue服务(8080端口,专门托管前端静态文件、反代后端接口)。HTTP模式下运行正常,一切换HTTPS就出问题,结合你贴的配置,大概率是这几个配置遗漏导致的:
- 443的server块没有绑定域名
你写的外层Nginx配置里,不管是80还是443的块,都没写server_name example.com;。如果这台主机上还跑着其他Nginx站点,HTTPS的请求很容易被路由到其他默认server块,那个块根本没配置你的反向代理规则,所有请求都会返回它自身的HTML页面,自然会触发JS加载报错。 - 请求路径透传错误
容器里的nginx-blue配了单页应用的兜底规则:找得到的文件就直接返回,找不到就返回index.html。要是外层Nginx代理的时候不小心改了请求路径(比如proxy_pass后面多写了个斜杠,或者加了莫名其妙的路径重写规则),JS请求的路径就会和容器里静态文件的实际存储路径对不上,触发兜底返回HTML,就会触发这个报错。 - 前端构建的资源路径和实际访问路径不匹配
要是构建前端的时候没设置对PUBLIC_URL环境变量,打出来的包里引用JS的路径和你HTTPS访问的根路径对不上,就会出现JS请求404,然后被兜底返回HTML的情况。
适配你这套蓝绿架构的修复步骤
- 第一步:先实锤问题
打开Chrome开发者工具的Network面板,勾选“禁用缓存”后刷新HTTPS页面,找到那两个报错的chunk.js请求,检查两个点:一是状态码是不是404,二是返回的内容是不是从<!DOCTYPE html>开头的。只要符合这两个特征,就是上面说的路径匹配问题,没有其他可能。 - 第二步:修正外层Nginx的配置
给80和443的server块都补上域名绑定,避免请求路由错位,改完后的核心配置如下:
改完运行upstream main { server <Internal-IP-to-docker-container>:8080; } server { listen 80; listen [::]:80; server_name example.com; # 新增域名绑定 location / { proxy_pass http://main; # 原有缓存配置保持不变 } } server { listen 443 ssl; listen [::]:443 ssl; server_name example.com; # 新增域名绑定 ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; location / { proxy_pass http://main; # 原有缓存配置保持不变 } }nginx -t校验配置无语法错误后,重载Nginx生效。注意proxy_pass后面别加末尾斜杠,不然Nginx会自动截断匹配的路径,把透传给容器的请求路径改得面目全非。 - 第三步:统一前端构建的资源路径
修改前端的Dockerfile,显式把资源根路径设为站点根目录,避免构建出来的资源路径和实际访问路径错位:
重新构建前端镜像、启动对应容器即可。FROM node:14.15.5-alpine3.10 USER root RUN mkdir /frontend WORKDIR /frontend COPY . /frontend RUN npm install --only=prod ENV PUBLIC_URL=/ # 新增资源根路径配置 RUN GENERATE_SOURCEMAP=false npm run-script build - 第四步:验证效果
按Ctrl+Shift+R强制刷新页面,清除本地缓存,在Network面板里确认JS请求返回200状态、Content-Type为application/javascript、内容是正常可执行的JS代码,问题就算解决了。
内容的提问来源于stack exchange,提问作者Joseph Hwang
相关产品推荐
相关产品推荐

