如何在不修改HTML文件的前提下将外部资源请求重定向到本地文件?
嘿,我来帮你理清楚这个问题——你之前的.htaccess规则没生效,核心原因其实很关键:浏览器是直接向foobar.com发起脚本请求的,这些请求根本不会经过你的服务器!哪怕页面是你服务器托管的,只要资源URL是外部域名,浏览器就会直接跳去那个域名拿资源,你的.htaccess根本抓不到这些请求,自然没法重写。
那有没有办法解决?当然有,给你两个靠谱的方案:
方案一:服务器端替换HTML内容 + 本地重写
思路是:在HTML文件从你的服务器发送到浏览器之前,把里面的外部资源链接替换成你自己服务器的路径,这样浏览器就会向你的服务器请求资源,再用rewrite规则把这个请求指向本地文件。
以Apache为例,你需要启用mod_substitute模块,然后在.htaccess里加这些配置:
# 先替换HTML里的外部资源链接为本地代理路径 AddOutputFilterByType SUBSTITUTE text/html Substitute "s|https://foobar.com/foo/scripts/script.js|/local-proxy/script.js|ni" # 再把本地代理路径重写到实际的本地文件 RewriteEngine On RewriteRule ^local-proxy/script\.js$ /js/script.js [L]
解释一下:第一部分会在HTML输出时,把所有指向foobar.com的脚本链接替换成你服务器的/local-proxy/script.js,浏览器收到页面后就会向你的服务器请求这个路径;第二部分的rewrite规则则把这个请求转发到你本地的/js/script.js文件。
方案二:用Service Worker拦截请求
Service Worker是运行在浏览器后台的脚本,它可以拦截当前页面发出的所有网络请求,包括外部域名的,然后你可以自定义这些请求的响应。
步骤如下:
- 先在你的服务器根目录创建一个
sw.js文件,内容如下:
self.addEventListener('fetch', function(event) { // 匹配目标外部资源的请求 if (event.request.url.startsWith('https://foobar.com/foo/scripts/script.js')) { // 替换成本地资源的请求 event.respondWith(fetch('/js/script.js')); } });
- 同样用服务器端注入的方式,在HTML里自动注册这个Service Worker(不用手动改HTML文件),还是用Apache的
mod_substitute:
AddOutputFilterByType SUBSTITUTE text/html Substitute "s|</body>|<script>if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js'); }</script></body>|ni"
这样浏览器加载页面时,会自动注册Service Worker,之后页面发出的所有请求都会被它拦截,匹配到目标外部脚本时,就会转而请求你本地的文件。
为什么你原来的方法不行?
再强调一遍:当HTML里写的是https://foobar.com/...的资源链接,浏览器会直接向foobar.com的服务器发送请求,这个请求的目标域名不是你的服务器,所以你的.htaccess完全接触不到这些请求,规则自然不会生效。
备注:内容来源于stack exchange,提问作者van_folmert




