如何使用 mod_rewrite 搜索和替换 GET 参数

How to search and replace GET parameters with mod_rewrite

我尝试在 httpd.conf 文件中的 apache 网络服务器配置上写一个重写规则,它应该将每个包含 &foo= 的 GET 参数键替换为 &poo= 但不应该更改任何其他 GET 参数。 例如:

https://test.com/imb/rs/search?test=abc&foo=123&test2=def&foo=456

应改为:

https://test.com/imb/rs/search?test=abc&poo=123&test2=def&poo=456

我试过:

RewriteCond %{QUERY_STRING} ^(.*)&foo=(.*)$
RewriteRule ^(.*)$ ?%1?&poo=%2 [NC]

但它只是将最后一次出现的 foo 更改为 poo。

我的 httpd.conf 文件结构如下:

<Directory ~ "^/imb/rs/*">
   Options Indexes FollowSymLinks
   AllowOverride All
   Order allow,deny
   Allow from all
   RewriteEngine on
   RewriteCond %{QUERY_STRING} ^(.*)&foo=(.*)$
   RewriteRule ^(.*)$ ?%1&poo=%2 [NC]
</Directory>

<IfModule mod_rewrite.c>
   RewriteEngine on
   RewriteCond %{QUERY_STRING} ^(.*)&foo=(.*)$
   RewriteRule ^(.*)$ ?%1&poo=%2 [NC]
</IfModule>

写/imb/rs/部分是因为url从https://test.com/imb/rs/开始,然后继续。我认为这符合我的情况。

有人知道我该如何解决这个问题吗?

我发现此解决方案仅适用于 1 次出现,不适用于多次出现。

这个只需要第一次出现:

RewriteCond %{QUERY_STRING} (.*?)foo(.*) [NC] 
RewriteRule ^ %{REQUEST_URI}?%1poo%2 [NC] 

这个只需要最后一次出现:

RewriteCond %{QUERY_STRING} (.*)foo(.*) [NC] 
RewriteRule ^ %{REQUEST_URI}?%1poo%2 [NC] 

但我找不到替换所有这些的方法。

<Directory ~ "^/imb/rs/*">
   Options Indexes FollowSymLinks
   AllowOverride All
   Order allow,deny
   Allow from all
   RewriteEngine on
   RewriteCond %{QUERY_STRING} ^(.*)&foo=(.*)$
   RewriteRule ^(.*)$ ?%1&poo=%2 [NC]
</Directory>

<IfModule mod_rewrite.c>
   RewriteEngine on
   RewriteCond %{QUERY_STRING} ^(.*)&foo=(.*)$
   RewriteRule ^(.*)$ ?%1&poo=%2 [NC]
</IfModule>

这里有一些问题。 <Directory> 容器不会匹配请求,因此不会处理此容器内的 mod_rewrite 指令。仅处理 <Directory> 容器外的 mod_rewrite 指令,但这只会替换查询字符串中 &foo=last 实例(因为正则表达式是 greedy 并且重写引擎只在 vHost/server 上下文中进行一次传递。

<Directory ~ "^/imb/rs/*">

您正在混合使用正则表达式和通配符语法。但是,这应该是绝对文件系统路径,而不是 URL-path,因为这看起来是(“url 以 https://test.com/imb/rs/”开头)。但是无论如何,您不需要在此处使用 <Directory> 指令的正则表达式版本。我假设 /imb/rs 是物理目录而不仅仅是虚拟目录 URL-path?

AllowOverride All

您正在明确启用 .htaccess 覆盖。如果您在该目录中确实有一个包含 mod_rewrite 指令的 .htaccess 文件,那么这将完全覆盖服务器配置中的 <Directory> 容器。您可能应该完全禁用 .htaccess 覆盖。

Order allow,deny
Allow from all

这些是 Apache 2.2 指令,以前在 Apache 2.4 上已弃用(我假设您正在使用它)。您应该使用等效的 Require all granted 来代替。 (但您确实需要确保自始至终都在使用 Apache 2.4 指令 - 不要将两者混用。)

Options Indexes FollowSymLinks

旁白:您是否有意允许 mod_autoindex 生成您内容的目录列表?通常,这应该被禁用(即从该规则中删除 Indexes)。

请尝试以下方法:

<Directory "/absolute/file/path/to/imb/rs">
   Options Indexes FollowSymLinks
   AllowOverride None
   Require all granted

   RewriteEngine On
   RewriteCond %{QUERY_STRING} (.*)&foo=(.*)
   RewriteRule (.*) ?%1&poo=%2 [L]
</Directory>

并从 <Directory> 容器外部删除规则。

所以,你一开始的规则基本没问题。这里不需要 start-of-string 和 end-of-string 锚点,因为正则表达式是 greedyNC 标志不是必需的。 L 标志不是严格要求的,但如果您稍后添加更多规则,则需要。