使用<base>-tag 是一个不错的解决方案,大多数浏览器似乎都能很好地处理它。除了 IE 有一些问题,这是意料之中的......显然你还可以遇到一些其他有趣的问题,see discussion here。
因此,对于无法选择的人,我已经研究了替代方案(“艰难的方式”)。
通常你会像这样存储 css/js/静态图片/其他东西:
index.php
js/
css/
imgs/
并且您希望 javascript 和样式表等可用,无论 url 中有多少斜杠。如果您的网址是/site/action/user/new,那么您的浏览器将请求
/site/action/user/css/style.css
/site/action/user/css/framework/fonts/icons.ttf
/site/action/user/js/page.js
/site/action/user/js/jquery/jquery.min.js
/site/action/user/js/some/library/with/deep/dir/structure/file.map
所以这里有一些apache的重写规则来解决这个问题...首先,如果目标确实存在于磁盘上,请不要重写:
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^.*$ - [L,QSA]
换句话说,如果请求文件名是目录或如果请求文件名是文件,则不要重写 (-)、最后一条规则 (L) 并传递任何 GET 参数(QSA、查询字符串附加)。你也可以使用
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -l
RewriteRule ^.*$ - [L,QSA]
如果您还需要符号链接。接下来,即使请求假定了错误的基目录,我们也希望找到 javascript 和样式表,如上所示。
RewriteRule ^.*/js/(.*)$ js/$1 [L]
RewriteRule ^.*/css/(.*)$ css/$1 [L]
模式很明显,只需将“css”替换为目录名称即可。这仍然存在问题,特别是对于具有大量 javascript 和样式表、库等的大型网站。- 正则表达式是贪婪的。例如,如果你有一个这样的 javascript 目录:
js/some/library/js/script.js
如果你的请求发送到/site/action/user/new,浏览器将请求/site/action/user/new/js/some/library/js/script.js,然后重写引擎将重写到
js/script.js
因为第一个.* 是贪婪的并且匹配/site/action/user/new/js/some/library。切换到非贪婪的正则表达式并没有真正意义,因为"the rewrite engine repeats all the rules until the URI is the same before and after an iteration through the rules."
还有一个问题,那就是对于每个需要免于重写的目录,都需要一个相对“昂贵”的正则表达式。这两个问题都可以通过将每个静态组件放入具有“不寻常”名称的子目录中来解决(实际上这是 imo 的最佳解决方案 - 任何有更好想法的人请发布)。
目录结构将如下所示:
index.php
mystrangedir/js/
mystrangedir/css/
mystrangedir/imgs/
当然,这需要在代码中的任何地方插入 - 对于具有大量现有代码库的项目,这可能会很棘手。但是,您只需要一个用于目录豁免的正则表达式:
RewriteRule ^.*/mystrangedir/(.*)$ mystrangedir/$1 [L]
自动构建系统(如 gulp、grunt....)可用于检查“mystrangedir”是否不存在于自身下方的目录中(这将再次引发重写引擎)。
随意将mystrangedir 重命名为更合理的名称,例如static_content,但越合理,目录名称就越有可能已在某个库中使用。如果您想要一个绝对安全的目录名称,并且之前肯定从未使用过,请使用加密哈希,例如010f8cea4cd34f820a9a01cb3446cb93637a54d840a4f3c106d1d41b030c7bcb。这是相当长的匹配;您可以通过缩短它来在唯一性和正则表达式性能之间进行权衡。