根据关键词更改URL特定部分的重写

huangapple go评论63阅读模式
英文:

URL Rewrite to change specific part of URL based on keyword

问题

每当有像这样的请求发送到服务器:

    https://%{HTTP_HOST}/app/accounturi/services

我想将其重定向到:

    https://%{HTTP_HOST}/appLegacy/accounturi/services

这里的 `accounturi` 将是动态的。我正在尝试在 apache2 中实现这个。

我尝试了下面的方法并在 RewriteRule 阶段卡住了:

    RewriteEngine On
    RewriteCond %{REQUEST_URI} ^/(.*)services/?$ [NC]
    RewriteRule ^(.*)$ https://%{HTTP_HOST}/appLegacy/

-------------------------------------------------------------

嘿,我很抱歉搞错了我的问题。我需要重写而不是重定向。

所以用户仍然应该能够看到:

    https://%{HTTP_HOST}/app/accounturi/services

但请求应该从这里获取响应:

    https://%{HTTP_HOST}/appLegacy/accounturi/services

请帮助我实现这个。我直接将这段代码写在了 apache2 默认配置的 

    <VirtualHost *:443>

下面。我已经在下面的 `<VirtualHost *:80>` 中启用了 HTTPS 重定向:

    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
英文:

Whenever there is a request like this to the server

https://%{HTTP_HOST}/app/accounturi/services

I want to redirect it to

https://%{HTTP_HOST}/appLegacy/accounturi/services

here accounturi will be a dynamic one. I'm trying this in apache2.

I tried the below and stuck on the RewriteRule.

RewriteEngine On
RewriteCond %{REQUEST_URI} ^/(.*)services/?$ [NC]
RewriteRule ^(.*)$ https://%{HTTP_HOST}/appLegacy/

Hey, I'm sorry that I messed up with my question. I need to rewrite not redirect.

So the user should still be able to see

https://%{HTTP_HOST}/app/accounturi/services

but the request should take the response from

https://%{HTTP_HOST}/appLegacy/accounturi/services

Please help with this. I'm directly writing this in the apache2 default configuration under

<VirtualHost *:443>

I already enabled HTTPS to redirect in below <VirtualHost *:80>

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

答案1

得分: 1

> RewriteCond %{REQUEST_URI} ^/(.)services/?$ [NC]
> RewriteRule ^(.
)$ https://%{HTTP_HOST}/appLegacy/

这将会将以 servicesservices/ 结尾的任何URL重定向为 https://<hostname>/appLegacy/,丢失了尾部的 <accounturi>/services 部分。

你也没有检查URL路径的开头是否包含 /app?(这让我觉得你的.htaccess文件是在/app子目录内?但没有其他内容表明如此。)

如果.htaccess文件位于/app子目录内,那么规则应该是这样的:

RewriteRule ^([^/]+/services)/?$ /appLegacy/$1 [R=302,L]

我假设URL路径中的动态部分 accounturi 由一个单一的路径段组成(与你的示例类似)。

前面的 RewriteCond 指令是不必要的。$1 回溯包含了从 RewriteRule 模式捕获的URL路径(这排除了请求中可能存在的任何可选的尾随斜杠)。注意,由于.htaccess文件位于/app子目录中,这被排除在捕获的URL路径之外。

你不需要指定一个绝对URL作为目标,因为你似乎是在同一 host 中进行重定向。然而,你可以选择包含这个来强制使用HTTPS。

然而,如果.htaccess文件位于文档根目录中,那么指令应该是这样的,并且要明确检查 /app 子目录:

RewriteRule ^app/([^/]+/services)/?$ /appLegacy/$1 [R=302,L]

更新 #1:

> 我想重写而不是重定向,并且我直接在默认配置页面中提到了这一点。

如果此规则直接用于 <VirtualHost: *:443>(根据你的更新),那么你需要调整规则如下:

RewriteRule ^/app/([^/]+/services)/?$ /appLegacy/$1 [L]

请注意,在 virtualhost 上下文中,RewriteRule 模式前面有一个斜杠前缀,因为 RewriteRule 模式匹配完整的相对于根的URL路径。并且移除了 R 标志。

这会在内部重写请求,而不是重定向。

另外:

> 我已经在下面的 <VirtualHost *:80> 中启用了HTTPS重定向。

在这里你不需要使用 mod_rewrite。一个简单的 mod_alias Redirect 就足够了,并且更有效率。并且这应该是一个 301(永久)重定向,而不是默认的 302(临时)重定向。例如:

Redirect 301 / https://example.com/

然而,你需要在规则中硬编码规范的主机名。

更新 #2:

> 有时我们在URL中不传递 'accounturi',所以在这种情况下它应该重写为 https://%{HTTP_HOST}/appLegacy/services 因此,accounturi 是一个可选的部分。

要使 accounturi(第二个路径段)变为可选项,请将规则更改为:

RewriteRule ^/app/(([^/]+/)?services)/?$ /appLegacy/$1 [L]

这基本上是使第二个路径段 [^/]+/(第二个路径段)成为可选项,通过将其放在括号中,后跟 ?。只有整个路径段是可选的,而不仅仅是分隔符 /(斜杠)。

另外:这也允许可选的尾随斜杠(从初始的“重定向”中保留下来)。由于现在是一个重写,如果不需要可选的尾随斜杠,那么它可能应该被移除,因为它可能会导致重复的内容(两个不同的URL返回相同的资源)。如果你确实需要允许带斜杠和不带斜杠的URL,那么应该在重写之前添加一个额外的规则,将一个重定向到另一个(规范的 URL)。

> 尝试了下面的。看起来工作得很好。

RewriteRule ^/app/((.*)+/?services)/?$ /appLegacy/$1 [L]

这个“工作”(在某种程度上),但有一些重大的缺陷:

  1. 非常低效。 使用 (.*)+ 子模式没有太多意义(零个或多个可能为空)。这个(不必要的)捕获子组实际上没有捕获任何内容,并使得正则表达式非常低效,因为它导致了大量的回溯。这个正则表达式与 ^/app/(.*/?services)/?$ 相同,但更高效。

  2. 匹配过多。 通过简单地将 /(在 services 之前)变为可选,这可能匹配得太多了,因为它匹配了 /app/<anything>services,其中包括像 /app/foo/bar/bazservices 这样的URL(请注意多个路径段和在 services 之前没有斜杠)。

英文:

> RewriteCond %{REQUEST_URI} ^/(.)services/?$ [NC]
> RewriteRule ^(.
)$ https://%{HTTP_HOST}/appLegacy/

This would 302 (temporary) redirect any URL that ends with services or services/ to https://&lt;hostname&gt;/appLegacy/, losing the trailing &lt;accounturi&gt;/services part.

You are also failing to check for /app at the start of the URL-path? (Which makes me think your .htaccess file is inside the /app subdirectory? But there is nothing else to suggest that.)

If the .htaccess file is located inside the /app subdirectory then the rule should be like this instead:

RewriteRule ^([^/]+/services)/?$ /appLegacy/$1 [R=302,L]

I'm assuming the dynamic accounturi part of the URL-path consists of a single path-segment (as in your example).

The preceding RewriteCond directive is not required. The $1 backreference contains the URL-path as captured from the RewriteRule pattern (this excludes any optional trailing slash that might be present on the request). Note that since the .htaccess file is inside the /app subdirectory, this is excluded from the URL-path that is captured.

You don't need to specify an absolute URL as the target since you appear to redirecting to the same host. However, you might choose to include this in order to enforce HTTPS.

If, however, the .htaccess file is in the document root then the directive would need to be like this instead and explicitly check for the /app subdirectory:

RewriteRule ^app/([^/]+/services)/?$ /appLegacy/$1 [R=302,L]

UPDATE#1:

> I want to rewrite not redirect . and I'm directly mentioning this in the default configuration page

If this rule is being used directly inside the &lt;VirtualHost: *:443&gt; (as per your update) then you would need to adjust the rule as follows:

RewriteRule ^/app/([^/]+/services)/?$ /appLegacy/$1 [L]

Note the slash prefix on the RewriteRule pattern, since in a virtualhost context the RewriteRule pattern matches the full root-relative URL-path. And the removal of the R flag.

This internally rewrites the request, as opposed to redirecting.


Aside:

> I already enabled HTTPS to redirect in below <VirtualHost :80>
>
> RewriteEngine On
> RewriteCond %{HTTPS} off
> RewriteRule (.
) https://%{HTTP_HOST}%{REQUEST_URI}

You don't need to use mod_rewrite here. A simple mod_alias Redirect would suffice and be more efficient. And this should be a 301 (permanent) redirect, not a 302 (temporary) which this will default to. For example:

Redirect 301 / https://example.com/

You would, however, need to hardcode the canonical hostname in the rule.


UPDATE#2:

> sometimes we don't pass 'accounturi' with the URL, so in that case it should rewrite to https://%{HTTP_HOST}/appLegacy/services So the accounturi is an optional one.

To make the accounturi (2nd path segment) optional then change the rule like this:

RewriteRule ^/app/(([^/]+/)?services)/?$ /appLegacy/$1 [L]

It basically makes the [^/]+/ part (2nd path segment) optional, by surrounding it in parentheses followed by ?. Only the entire path segment is optional, not just the delimiting / (slash).

Aside: This also allows an optional trailing slash (carried over from the initial "redirect" above). Since this is now a rewrite, the optional trailing slash should probably be removed if it's not required since it potentially promotes duplicate content (two different URLs returning the same resource). If you did need to allow URLs with and without a trailing slash then an additional rule should be added (before the rewrite) that redirects from one to the other (the canonical URL).

> tried the below. Seems it's working fine.
>
> RewriteRule ^/app/((.*)+/?services)/?$ /appLegacy/$1 [L]

This "works" (kind of) but has a couple of big flaws:

  1. Very inefficient. The use of the (.*)+ subpattern doesn't make much sense (one or more of potentially nothing). The (unnecessary) capturing subgroup does not actually capture anything and makes the regex very inefficient as it results in an enormous amount of backtracking. This regex is the same as ^/app/(.*/?services)/?$, which is more efficient. But...

  2. Matches too much. By simply making the / (before services) optional this potentially matches far too much, since it matches /app/&lt;anything&gt;services, which includes URLs like /app/foo/bar/bazservices (note the multiple path segments and no slash before services).

huangapple
  • 本文由 发表于 2023年4月17日 18:52:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76034364.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定