RewriteCond 适用于 HTTP,但不适用于 HTTPS 虚拟主机

Posted

技术标签:

【中文标题】RewriteCond 适用于 HTTP,但不适用于 HTTPS 虚拟主机【英文标题】:RewriteCond works on HTTP but not on HTTPS virtual host 【发布时间】:2022-01-11 00:14:17 【问题描述】:

我想重写所有带有尾随“.pdf”的 URL,以打开 mozilla.pdf.js 中的 pdf 文件,并在我的 HTTP 虚拟主机上成功地测试了 RewriteRule 和 RewriteCond(我在 ubuntu 服务器上使用 apache2) :

要重写的示例 URL:

http://server-test.local/downloads/dir2/file5/test.pdf

重写后的示例目标 URL:

http://server-test.local/libs/mozilla.pdf.js/web/viewer.html?file=/downloads/dir2/file5/test.pdf
RewriteCond %HTTP_REFERER !viewer.html
RewriteRule ^(.+)(\.pdf)$ http://server-test.local/libs/mozilla.pdf.js/web/viewer.html?file=$1 [R=301,L]

所以RewriteCond 阻止了另一个重定向,这将导致mozilla.pdf.js 尝试加载自身而不是PDF 文件并导致错误。 (对不起,如果描述不清楚,我不是很喜欢这个话题)

现在我尝试为我的其他虚拟主机 (https) 应用完全相同的 RewriteCond 和 RewriteRule,除了 SSL 和 Kerberos 实现之外,它与“服务器测试”虚拟主机完全相同:

RewriteCond %HTTP_REFERER !viewer.html
RewriteRule ^(.+)(\.pdf)$ https://server-prod.local/libs/mozilla.pdf.js/web/viewer.html?file=$1 [R=301,L]

但似乎不知何故 RewriteCond 不适用。结果是,重定向到mozilla.pdf.js 有效,但不会呈现PDF,并且会出现mozilla.pdf.js 的错误(“无效的PDF 结构”),因为-这是我的理论-还有另一个重定向,所以mozilla.pdf.js 不会加载/渲染pdf,而是尝试加载自己的viewer.html

我也尝试了以下RewriteConds,但没有一个人改变了行为:

RewriteCond %REQUEST_URI !viewer.html*
RewriteCond %REQUEST_URI !^/libs/mozilla.pdf.js/web/viewer.html*
RewriteCond !viewer.html

我使用这些RewriteConds 的目的是防止另一个(循环)重定向,如果重写之前的 URL 包含字符串“viewer.html”,那么如果[...]/viewer.html?file=/downloads/dir2/file5/test.pdfREQUEST_URI,则不应再重写发生。

有人可以向我解释一下,为什么 RewriteCond 可以在测试虚拟主机 (HTTP) 上运行,但不能在生产虚拟主机 (HTTPS) 上运行?除了 SSL 和 SSL 安全虚拟主机具有 Kerberos 实现这一事实外,这两个虚拟主机、它们的目录和配置大多相同。 SSL是问题吗?有谁知道我如何在 SSL 虚拟主机上解决这个问题?我需要以某种方式找到解决方案...

我将不胜感激各种提示/帮助。

【问题讨论】:

【参考方案1】:

重写后的示例目标 URL:http://example.com/libs/mozilla.pdf.js/web/viewer.html?file=/downloads/dir2/file5/test.pdf

但是,您的指令目前不这样做。它重定向(不是“重写”)到http://example.com/libs/mozilla.pdf.js/web/viewer.html?file=downloads/dir2/file5/test - 请注意file URL 参数值开头缺少的斜杠和缺少的文件扩展名。

如果在前者上启用了 MultiViews,这可能在一台服务器上运行,而在另一台服务器上运行。 (这有效地使无扩展 URL 能够“工作”。)

更正RewriteRule 指令:

RewriteRule \.pdf$ https://example.com/libs/mozilla.pdf.js/web/viewer.html?file=%REQUEST_URI [R=301,L]

file URL 参数现在将包含 /downloads/dir2/file5/test.pdf

您需要在测试前清除浏览器缓存。但是,这应该是 301(永久)重定向吗?您在问题中提到了“重写”,并且您已标记问题url-rewriting - 这不是。您是否希望用户在物理上被重定向到这个新 URL?看起来这真的应该是一个内部重写(即不暴露mozilla.pdf.js)?在这种情况下,应该像下面这样重写:

RewriteRule \.pdf$ /libs/mozilla.pdf.js/web/viewer.html?file=%REQUEST_URI [L]

出现 mozilla.pdf.js 的错误(“无效的 PDF 结构”),因为 - 那是我的理论 - 还有另一个重定向,所以 mozilla.pdf.js 不会加载/渲染 pdf,但它会尝试而是加载它自己的 viewer.html。

虽然如果是这种情况,那么它会导致重定向循环,但您看到的错误并不表示这一点。

另外,您是否确认浏览器正在为此请求发送Referer HTTP 请求标头并且已按预期设置?这里的问题是Referer不可靠的。它可以被浏览器抑制有几个原因。

如果mozilla.pdf.js 将自定义标头设置为请求的一部分,并且这可以在 mod_rewrite 条件中可靠地检查,则更好的方法是。

或者,使 URL 路径与实际文件系统路径不同。 (尽管如果文件路径已知,则可以请求实际文件。)


旁白:

所以RewriteCond 阻止了另一个重定向,这将导致mozilla.pdf.js 尝试加载自身而不是 PDF 文件并导致错误。

它不会尝试加载“自身”。 RewriteRule 模式已经可以防止这种情况发生,因为它只匹配 .pdf 文件(尽管这不是这里发生的事情)。对Referer 的检查是为了防止递归循环...防止viewer.html 被重复调用并在file URL 参数中传递相同的.pdf 文件。

我假设mozilla.pdf.jsfile URL 参数中传递的PDF 文件发出HTTP 请求。 “问题”(在外部重定向的情况下)是区分来自用户的直接请求和来自脚本的请求(两者都是来自浏览器的客户端请求)。

【讨论】:

感谢您的提示。我已经尝试了您给我的两种解决方案。我还检查了是否在标题中给出了引用者,是的,我能够在标题中找到正确的引用者。我还比较了 MS Edge 的开发者工具中加载的文件。区别:在工作的虚拟主机上,网络选项卡中显示的最后一个加载文件是“test.pdf”。在非工作文件中,网络选项卡中显示的最后一个文件是 viewer.html?file=[...]。我还注意到,在 test.pdf 的答案标题中,给定的内容类型是 text/html 而不是 application/pdf,正如我所期望的那样。【参考方案2】:

我想,我可以通过另外添加来解决我的问题

RewriteCond %QUERY_STRING !file=

到我的 RewriteRule 的 RewriteConds。现在 mozilla.pdf.js 打开并显示 PDF 文件。 @MrWhite 再次感谢您的解释。

【讨论】:

以上是关于RewriteCond 适用于 HTTP,但不适用于 HTTPS 虚拟主机的主要内容,如果未能解决你的问题,请参考以下文章

Codeigniter 3,适用于“http”但不适用于“https”

Apache 重写到新文件夹不起作用(适用于现有文件夹)

部分视图部分适用于 JQuery,但不完全适用于 C# ASP.Net MVC 5

为啥逻辑适用于函数但不使用类,合并排序算法

vue中将汉字按照首字母排序,也适用于其他地方,但不适用多音字

路径重写,适用于laravel,yii