MERN栈部署Apache后刷新或直接访问URL报404问题排查
核心根因
你写在Express里的静态托管、通配兜底路由完全没有生效,本质原因是当前部署架构下,只有/api路径的请求被Apache转发到了Node服务,其余所有路径请求全由Apache直接处理静态资源响应,Express根本接不到这些非API请求,对应的路由规则自然不会触发。
你做的同名图片测试已经验证了这个逻辑:Apache收到路径请求时,会优先匹配静态目录下的物理文件/目录,找到就直接返回资源,找不到就直接返回404,完全没有把请求交给前端路由处理的逻辑,这就是刷新、直接输入子路径URL报404的直接原因。
之前能正常运行、旧版本代码重新部署也复现问题,就是因为服务器侧Apache配置被改动过,丢失了前端路由对应的重写兜底规则,和代码版本无关。
修复步骤(推荐方案:Apache直接托管静态资源,性能最优)
这是前后端分离部署下Apache托管前端静态资源的标准配置,不需要依赖Express处理静态路由:
- 第一步:启用Apache重写模块
服务器终端执行以下命令启用rewrite模块:sudo a2enmod rewrite - 第二步:修改站点配置
找到Apache下对应站点的配置文件,通常存放在/etc/apache2/sites-available/目录下,注意HTTP(80端口)和HTTPS(443端口)对应的配置都要修改,否则两个协议会有一个复现问题。
在配置中找到指向前端打包后静态资源目录的<Directory>配置段,修改为如下内容,注意把路径替换为你自己服务器上静态资源的实际存放路径:<Directory /var/www/你的站点静态资源实际路径> Options Indexes FollowSymLinks AllowOverride All Require all granted # 客户端路由兜底重写规则 RewriteEngine On RewriteBase / # 请求对应物理文件存在时,直接返回文件,不重写 RewriteCond %{REQUEST_FILENAME} !-f # 请求对应物理目录存在时,直接返回目录,不重写 RewriteCond %{REQUEST_FILENAME} !-d # 排除/api路径的接口请求,不做重写 RewriteCond %{REQUEST_URI} !^/api # 其余所有请求统一返回index.html,交给前端客户端路由处理 RewriteRule . /index.html [L] </Directory> - 第三步:清理冲突测试文件
删掉你之前放在静态目录下名为register的测试图片,这类和前端路由路径重名的物理文件,会被上面的规则优先匹配返回,导致路由异常。 - 第四步:校验配置并重启服务
执行命令校验Apache配置是否正确,避免配置错误导致服务中断:
命令返回sudo apache2ctl configtestSyntax OK后,重启Apache服务让配置生效:sudo systemctl restart apache2
可选方案(走Express处理静态资源与路由兜底)
如果你确实需要让Express接管所有非API请求的处理,只需要调整Apache的代理规则,不要仅代理/api路径,而是按优先级配置全量代理:
- 调整站点配置中的代理规则顺序,高优先级路径写在前面:
ProxyPass /api http://127.0.0.1:你的Node服务监听端口/api ProxyPassReverse /api http://127.0.0.1:你的Node服务监听端口/api ProxyPass /static http://127.0.0.1:你的Node服务监听端口/static ProxyPassReverse /static http://127.0.0.1:你的Node服务监听端口/static ProxyPass / http://127.0.0.1:你的Node服务监听端口/ ProxyPassReverse / http://127.0.0.1:你的Node服务监听端口/ - 校验配置重启Apache后,你之前写在Express里的静态托管、通配兜底路由就会正常生效。该方案静态资源响应性能弱于Apache直接托管,非特殊需求不推荐使用。
验证标准
- 直接在地址栏输入任意子路由路径(如
/register),可正常加载对应页面,不返回404 - 在任意子路由页面执行刷新操作,页面正常加载,不出现404
/api路径下的所有接口请求正常转发,功能不受影响- 静态资源(JS、CSS、图片等)正常加载,不被重写规则拦截
内容的提问来源于stack exchange,提问作者lilolme
相关产品推荐
相关产品推荐

