如何用.htaccess重定向除指定目录外的子目录,避免404及资源加载异常?
解决History API刷新404的.htaccess规则方案
你的问题本质是单页应用(SPA)的路由兼容问题——用History API修改URL后,服务器上并没有对应的物理目录,所以刷新会返回404。要实现「除assets和download外的请求都指向根目录」,同时不破坏静态资源加载,我们需要调整.htaccess的重写规则,而不是单纯依赖正则匹配。
正确的.htaccess配置
直接用下面的规则替换你现有的配置,它会完美满足需求:
RewriteEngine On # 1. 放行真实存在的文件/目录(比如assets下的CSS、图片,download下的文件) RewriteCond %{REQUEST_FILENAME} -f [OR] RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^ - [L] # 2. 排除assets和download目录的所有请求 RewriteCond %{REQUEST_URI} !^/assets/ RewriteCond %{REQUEST_URI} !^/download/ # 3. 将剩余请求内部重写到根目录入口文件(保持URL不变,前端JS处理路由) RewriteRule ^ /index.html [L]
规则解释
- 放行真实资源:第一部分的规则会优先检查请求的文件或目录是否真实存在,如果是(比如
/assets/css/style.css或/download/report.pdf),直接放行不做任何修改,确保静态资源正常加载。 - 排除指定目录:通过
RewriteCond排除以/assets/和/download/开头的所有请求,即使这些目录下有子文件夹(比如/assets/img/logo.png),也不会被重写。 - 内部重写路由:最后一条规则将所有不符合上述条件的请求(也就是你用History API创建的虚拟路由,比如
/product/123)内部重写到index.html,服务器返回根目录的页面,前端JS就能读取当前URL并渲染对应的模态框或页面内容,不会出现404。
你之前正则的问题
你写的(\/(?!assets|download).*)正则存在两个问题:
- 它没有结合「真实文件/目录检查」,如果
/assets/下的子目录不存在(比如/assets/non-exist/),会被错误匹配并重定向,破坏资源加载逻辑; - 负向预查的匹配范围不对,它会尝试匹配
/后不是完整的assets或download开头的内容,比如如果有个路径是/assetss/xxx(多了一个s),会被错误匹配,但你实际需要的是完全排除/assets/和/download/开头的所有请求。
可选:外部重定向(如果需要URL跳转到根目录)
如果你确实希望刷新后URL直接跳转到根目录(而不是保持原URL),可以把最后一条规则改成:
RewriteRule ^ / [R=302,L]
不过更推荐用内部重写的方式,这样能保留用户的路由状态,符合History API的使用场景。
内容的提问来源于stack exchange,提问作者zuddsy
相关产品推荐
相关产品推荐

