Heroku部署React+Rails应用客户端路由报404问题求助
问题原因
刷新/直接访问子路由返回404是SPA应用部署的典型问题:React Router为客户端路由,路由切换在浏览器端完成,直接访问/user这类子路径时,请求会直接发送到Heroku服务端,服务端无对应路径处理规则就会返回404。
你编写的static.json不生效,核心原因是该配置仅对Heroku的create-react-app-buildpack静态托管规则生效,如果你使用Ruby on Rails托管React构建产物,Rails路由优先级高于静态文件规则,这个配置完全不会被加载。
解决方案
针对React+Ruby on Rails全栈部署的场景,优先选择Rails侧配置兜底路由的方案,稳定性最高:
方案1:Rails托管前端静态文件(全栈项目推荐)
- 确认React构建输出路径
如果你使用Create React App搭建React项目,修改前端目录下的package.json,指定构建产物输出到Rails默认托管静态资源的public/build目录(如果前端代码存放在/client子目录,就修改client/package.json):
如果前端代码不在仓库根目录,需要在仓库根目录的{ "scripts": { // 保留原有其他脚本,仅修改build命令指定输出路径 "build": "BUILD_PATH=../public/build react-scripts build" } }package.json添加脚本,确保Heroku部署时自动执行前端构建:{ "scripts": { "postinstall": "npm run build", "build": "cd client && npm ci && npm run build" } } - 开启Rails生产环境静态文件服务
打开config/environments/production.rb,确认存在以下配置,避免环境变量缺失导致静态文件无法访问:config.public_file_server.enabled = true - 添加Rails兜底路由
打开config/routes.rb,在所有路由定义的最末尾添加以下规则,把所有非API的HTML请求转发到React入口文件,交给React Router接管路由:
配置完成后提交代码重新部署到Heroku即可生效。# 注意:必须放在所有其他路由的最下方,避免覆盖正常的后端接口、后台页面路由 get '*path', to: proc { |env| request = Rack::Request.new(env) # 仅处理HTML请求,排除/api开头的后端接口路径,可根据实际接口前缀修改判断规则 if request.format.html? && !request.path.start_with?('/api/') # 如果React构建产物直接输出到public根目录,删掉路径中的'build'段即可 index_path = Rails.root.join('public', 'build', 'index.html') [200, { 'Content-Type' => 'text/html' }, [File.read(index_path)]] else [404, { 'Content-Type' => 'text/plain' }, ['Not Found']] end }
方案2:前后端分离部署,前端用静态buildpack托管
如果你采用前后端分离架构,Rails仅提供API接口、前端通过Heroku静态buildpack托管,按以下步骤修复:
- 本地安装Heroku CLI后,在项目根目录执行命令配置正确的buildpack顺序:
heroku buildpacks:clear heroku buildpacks:add heroku/nodejs heroku buildpacks:add mars/create-react-app heroku buildpacks:add heroku/ruby - 修正根目录下的
static.json配置,root路径必须填写相对于仓库根目录的构建产物路径(如果React项目在client子目录,就写client/build/):{ "root": "build/", "clean_urls": true, "routes": { "/**": "index.html" } }
注意事项
- 不要为了临时规避问题将
BrowserRouter替换为HashRouter,该方案会让URL携带#段,影响URL美观度和SEO效果。 - 兜底路由必须放在所有后端路由的最末尾,否则会拦截正常的接口、后台页面请求。
内容的提问来源于stack exchange,提问作者Brad Bieselin
相关产品推荐
相关产品推荐

