BrowserRouter路由异常:CI部署后URL变更但页面不跳转
环境配置
部署环境 托管:通过CloudFront访问的S3存储桶 CI:Github Actions + Terraform CloudFront自定义404错误页设置为index.html(返回200状态码) S3错误页设置为index.js Node版本:16.10.0 React版本:18.2.0 补充:React Router Dom版本6.12.1,使用BrowserRouter组件
问题描述
React应用通过CI构建部署后,React Router仅变更URL但页面不跳转,只有强制刷新才能正常显示目标页面。本地开发、手动构建后通过AWS控制台上传至S3时,路由导航均正常。
CI流程仅执行npm install && npm run build,已确认MIME类型设置正确,但无法定位差异点,卡了好几天,求解决思路。
相关配置
Terraform部署文件资源配置
resource "aws_s3_bucket_object" "app_files" { for_each = fileset("${path.module}/app/build", "**/*.*") bucket = aws_s3_bucket.app_bucket.id key = each.value source = "${path.module}/app/build/${each.value}" etag = filemd5("${path.module}/app/build/${each.value}") content_type = lookup(var.mime_types, split(".", each.value)[length(split(".", each.value)) - 1], "application/octet-stream") }
CloudFront分发配置
resource "aws_cloudfront_distribution" "app_distribution" { origin { domain_name = aws_s3_bucket.app_bucket.website_endpoint origin_id = aws_s3_bucket.app_bucket.id custom_origin_config { http_port = 80 https_port = 443 origin_protocol_policy = "http-only" origin_ssl_protocols = ["TLSv1.2"] } } restrictions { geo_restriction { restriction_type = "none" } } enabled = true is_ipv6_enabled = true default_root_object = "index.html" aliases = [var.service_domain] default_cache_behavior { allowed_methods = ["GET", "HEAD"] cached_methods = ["GET", "HEAD"] target_origin_id = aws_s3_bucket.app_bucket.id forwarded_values { query_string = false cookies { forward = "none" } } viewer_protocol_policy = "redirect-to-https" min_ttl = 0 default_ttl = 3600 max_ttl = 86400 } viewer_certificate { acm_certificate_arn = var.main_certificate_arn ssl_support_method = "sni-only" } custom_error_response { error_code = 404 response_code = 200 response_page_path = "/index.html" error_caching_min_ttl = 0 } }
路由JSX配置
<Router> <Routes> <Route // 移除末尾斜杠 path="*(/+)" loader={({ params }) => redirect(params['*'] || '/')} /> {appStore?.auth?.accessToken ? ( <Route path="" element={<Template />}> <Route exact path="/" element={<Navigate to={ROUTES.MY_MIRRORS} />} /> ... 其他应用路由 <Route path="/forbidden" element={<Pages.ErrorBoundaryForbidden />} /> <Route path="/404" element={<Pages.ErrorBoundary404 />} /> <Route path="*" element={<Navigate replace to={ROUTES.MY_MIRRORS} />} /> </Route> ) : ( <Route path="" element={<UnauthenticatedTemplate />}> <Route path="/login" element={<Pages.Login />} /> <Route path="/register" element={<Pages.NewUser />} /> <Route path="/contact" element={<Pages.Contact />} /> <Route path="/privacy-policy" element={<Pages.PrivacyPolicy />} /> <Route path="/" element={<Pages.Home />} /> <Route path="*" element={<Navigate replace to="/login" />} /> </Route> )} </Routes> </Router>
导航实现(useNavigate钩子)
import { useNavigate } from 'react-router-dom'; ... const navigate = useNavigate(); ... <Button color="gray" onClick={() => navigate('/contact')}> Contact Us </Button>
补充说明:移除CI构建步骤,改为本地构建后提交build文件夹由CI部署,一切正常。问题可确定出在CI执行构建的环节。
可能的解决方向
- 锁定CI环境的依赖版本:本地和CI的npm/yarn版本、依赖包版本可能不一致,导致构建产物差异。可以在CI步骤中指定和本地一致的npm版本,或确保
package-lock.json/yarn.lock被正确提交,强制CI安装与本地完全相同的依赖。 - 显式设置构建环境变量:在CI构建命令中添加
NODE_ENV=production,比如NODE_ENV=production npm run build,避免环境变量差异导致路由逻辑异常。 - 检查React Router的base路径:在
BrowserRouter中显式设置basename="/",确保路由根路径匹配部署环境,比如:<BrowserRouter basename="/"> {/* 路由内容 */} </BrowserRouter> - 验证CI构建的工作目录:确保CI执行
npm run build的目录与本地一致,避免路径错误导致构建产物异常。 - 添加CloudFront缓存失效步骤:CI部署完成后,触发CloudFront缓存失效,确保用户获取到最新的构建产物,排除缓存旧资源导致的路由问题。
- 检查环境变量注入:如果应用依赖
REACT_APP_*等环境变量,确认CI构建时这些变量已正确注入,避免缺失变量引发路由逻辑错误。
内容的提问来源于stack exchange,提问作者MichaelTaylor3D
相关产品推荐
相关产品推荐

