htaccess RewriteRule使用字面问号(而不是查询字符串)

4

我需要能够匹配问号,因为翻译文本编码错误,导致URL的一部分硬编码有问号。这是一个需要重写的URL示例:

https://example.com/Documentation/Product????/index.html

这是我当前的重写规则。当“Product”后面的字符不是问号时,它是有效的,但当它们是问号时,规则不适用。

RewriteRule "^Documentation/Product[^/]+/(.*)$" "https://s3.amazonaws.com/company-documentation/Help/Product/$1" [L,NC]

我该如何确保问号在这个规则中被视为字符?我不能期望只有问号而不是原来的非英文字符出现在URL中,所以我想让上面的规则匹配问号和任何其他字符。
我发现了这个相关的主题,但标志无济于事,并且答案没有解释如何克服"Aside"中提到的问题。 https://webmasters.stackexchange.com/questions/107259/url-path-with-encoded-question-mark-results-in-incorrect-redirect-when-copied-to

这个是否应该与您现有的规则一起工作?例如,您是否有形式为/Documentation/Product<something>/<optional-end-part>的URL,重定向到https://s3.amazonaws.com/company-documentation/Help/Product/<optional-end-part>index.html是可变的吗?即使在这些格式不正确的URL中也是如此? - MrWhite
index.html 部分是可变的。我有其他针对“正常”URL的规则。这个规则只需要作为产品的最后手段来捕捉奇怪的URL。 - Cohaven
除了可能看起来相关之外,链接的问题与此问题并不直接相关。在链接的问题中,源URL在URL路径中具有“文字”问号(即问题标记已进行URL编码),因此没有查询字符串(问题#1)。这也被捕获(问题#2)并传递给替换(问题#3)。链接问题中的“旁注”实际上并没有描述“问题”,只是一个过程。您可以使用“NE”标志防止后续的“?”被URL编码,但这未必是理想的。 - MrWhite
1个回答

1
https://example.com/Documentation/Product????/index.html
你说这不是一个“查询字符串”,但实际上它确实是。这就是为什么你不能用 RewriteRule 模式 来匹配它的原因。上面的URL被拆分如下:
  • URL路径:/Documentation/Product(与RewriteRule 模式匹配)
  • 查询字符串:???/index.html(注意3个问号 - 第一个开始查询字符串)
为了匹配查询字符串,您需要使用额外的 RewriteCond 指令来检查 QUERY_STRING 服务器变量。
例如,要匹配上面的URL,您需要做以下操作:
RewriteCond %{QUERY_STRING} ^\?*/index\.html
RewriteRule ^Documentation/Product$ https://s3.amazonaws.com/company-documentation/Help/Product/index.html [NC,R,L]

这将匹配查询字符串开头的任意数量的错误 ?。我添加了 R (redirect) 标志。您的指令(不带 R 标志)将触发外部重定向(因为您在 替换 中指定了绝对 URL),但在此处明确更好。这也是一个临时的 (302) 重定向。如果应该是永久的 (301),则将其更改为 R=301,但只有在确认它正常工作后才更改(301 被浏览器硬缓存,因此可能会导致测试问题)。

更新:

...所以我希望上述规则可以匹配问号和任何其他字符。

只有当URL中有问号时,才会有查询字符串,因此我认为将这两个规则分开是明智的。

如果查询字符串开头可能有任何错误字符,并且您想捕获URL的结尾部分(就像在原始指令中所做的那样,例如index.html),则可以修改上述内容:

RewriteCond %{QUERY_STRING} /(.*)$
RewriteRule ^Documentation/Product$ https://s3.amazonaws.com/company-documentation/Help/Product/%1 [NC,R,L]

请注意在替换字符串中的 substitution 中,使用了 %1(而不是 $1)反向引用。这是对上一个匹配的 CondPattern(即 /(.*)$)中捕获组的反向引用。

您可以在现有指令后面跟随此操作(但记得包括 R 标志),以处理更多不包含 ?(即查询字符串)的“正常” URL。

注意:在此示例中,用双引号括起参数完全是可选的。只有在 patternsubstitution 参数中存在 未转义的空格 时才需要它们。

总结

# Redirect URLs of the form:
# "/Documentation/Product?<anything#1>/<anything#2>"
RewriteCond %{QUERY_STRING} /(.*)$
RewriteRule ^Documentation/Product$ https://s3.amazonaws.com/company-documentation/Help/Product/%1 [NC,R,L]

# Redirect URL-paths of the form (no query string):
# "/Documentation/Product<something>/<anything>"
RewriteRule ^Documentation/Product[^/]+/(.*) https://s3.amazonaws.com/company-documentation/Help/Product/$1 [NC,R,L]

这似乎与我所读到的关于 URL 中第一个问号的内容一致。我稍后会尝试一下。谢谢! - Cohaven
我已经根据您的评论和更新的问题,更新了我的答案,提供了更“通用”的解决方案。 - MrWhite

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接