You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apache2部署React时存在的CSS/JS文件被重定向到index.html问题

问题根本原因

该问题是Apache缓存机制、配置逻辑、部署流程三类问题叠加导致,和你之前清理的mod_cache_disk磁盘缓存没有直接关系:

  • Apache文件系统元数据缓存默认TTL最长为3600秒(1小时):Apache会缓存所有文件存在性、修改时间等stat调用结果,你上传新文件后,工作进程仍持有旧的缓存记录,判定新的static/css/main.8b985c6c.chunk.css不存在,直接触发重写规则返回index.html。平滑重启Apache不会强制清空工作进程的这部分缓存,必须完全停止再启动才会触发全量刷新,而静置1小时后缓存自动过期,重新校验文件系统发现文件存在,服务就自行恢复。
  • 部署操作非原子导致的文件状态不一致:如果部署时采用先删除旧文件再上传新文件、或直接覆盖写入的方式,会存在几秒到几十秒的时间窗口,期间部分文件已删除、部分文件未上传完成;再叠加Apache默认开启的EnableSendfile、EnableMMAP特性会持有旧文件句柄,会进一步拉长文件状态不一致的窗口,此时请求进来要么判定文件不存在触发重写,要么读取到未替换完成的旧版index.html。
  • 配置规则存在逻辑缺陷:一是给所有带hash的JS、CSS资源设置了强制不缓存头,导致浏览器每次都回源请求静态资源,大幅提升了部署窗口期请求命中异常状态的概率;二是重写规则顺序错误,HTTPS跳转规则前置且使用了[END]标记,在Apache 2.4.41版本中会中断后续的文件存在性校验逻辑,偶发将已存在的静态资源也重写到index.html。
    你看到访问新CSS路径返回旧版index.html、旧版index.html引用的旧CSS反而能加载的现象,就是因为元数据缓存里旧CSS的存在性记录还没过期,而新CSS的存在性没被缓存、index.html的内容缓存还停留在旧版本,三者叠加出现的反常状态。
修复方案

按以下步骤调整即可彻底解决该重复出现的部署问题:

  1. 调整Apache站点主配置(.htaccess无权修改该级参数),关闭静态文件句柄缓存,缩短元数据缓存周期
    在对应站点的VirtualHost配置段中加入以下内容:
    # 关闭文件句柄映射缓存,避免覆盖上传时读取到旧文件内容
    EnableMMAP Off
    EnableSendfile Off
    # 按文件修改时间和大小生成ETag
    FileETag MTime Size
    
    修改完成后执行systemctl restart apache2完全重启服务,不要使用reload平滑重启。
  2. 替换现有.htaccess配置,修正缓存策略和重写规则顺序
    # 带内容hash的静态资源设置1年强缓存,内容变更时hash会同步变化,无需回源校验
    <FilesMatch "\.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$">
      FileETag None
      <IfModule mod_headers.c>
        Header unset ETag
        Header set Cache-Control "max-age=31536000, immutable"
      </IfModule>
    </FilesMatch>
    
    # 仅对HTML入口文件设置强制不缓存,保证用户始终拿到最新的资源引用
    <FilesMatch "\.(html|htm)$">
      FileETag None
      <IfModule mod_headers.c>
        Header unset ETag
        Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
        Header set Pragma "no-cache"
        Header set Expires "Wed, 12 Jan 1980 05:00:00 GMT"
      </IfModule>
    </FilesMatch>
    
    <IfModule mod_rewrite.c>
      RewriteBase /
      # 优先校验文件/目录/软链接是否存在,存在则直接返回不触发重写
      RewriteCond %{REQUEST_FILENAME} -f [OR]
      RewriteCond %{REQUEST_FILENAME} -d [OR]
      RewriteCond %{REQUEST_FILENAME} -l
      RewriteRule ^ - [L]
    
      # 非HTTPS请求跳转
      RewriteCond %{HTTPS} off
      RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L,NE,R=permanent]
    
      # 其余所有不存在的路径统一重写到入口index.html,适配React路由
      RewriteRule ^ index.html [L]
    </IfModule>
    
  3. 调整部署流程为原子替换,消除文件不一致窗口
    部署时不要直接往运行中的站点目录上传/覆盖文件,先将React构建产物上传到同磁盘的临时目录,确认文件权限、属主正确后,用mv命令做原子替换:
    # 示例路径替换为实际站点路径
    rm -rf /var/www/site_old
    mv /var/www/site /var/www/site_old
    mv /var/www/site_temp /var/www/site
    # 执行优雅重启加载新配置
    systemctl reload apache2
    
    整个目录替换过程是原子操作,耗时仅几毫秒,不会出现中间状态。

内容的提问来源于stack exchange,提问作者David MOSCA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 18:48:26