Reputation: 33
I'm trying to add an anchor to an URL with a query string. The original URL is
https://example.com/foo?query=123
It should redirect to
https://example.com/foo?query=123#anchor
These are my Rules in the .htaccess
file:
RewriteCond %{REQUEST_URI} ^/foo$
RewriteCond %{QUERY_STRING} ^query=[a-zA-Z0-9\s]*$
RewriteRule (.*) /foo?%{QUERY_STRING}#anchor [NC,NE,R=302,L,END]
Do you have an idea how to avoid the redirecting loop?
Upvotes: 3
Views: 267
Reputation: 45923
Do you have an idea how to avoid the redirecting loop?
This is not possible with a server-side (Apache / .htaccess
) redirect, without changing the URL-path or query string in some way.
The #anchor
(or fragment identifier) is not passed to the server in the redirected request, so the same URL matches your rule and triggers another redirect to append #anchor
, again and again, etc.
When you request /foo?query=123
, the request is 302 redirected to /foo?query=123#anchor
(the rule you've posted already does that). However, the browser only sends /foo?query=123
(no fragment identifier) back in the redirected request so the process starts over.
The only way to prevent the redirect loop in your "server-side" redirect is to change other elements of the URL in someway that you can then detect in you rule. eg. redirect to /bar?query=123#anchor
or /foo?query=123&noredirect=1#anchor
etc.
However, fragment identifiers (#anchors
) are only used by the client-side script/HTML, so if #anchor
is required on the URL then this should be added using JavaScript instead.
Aside: Just a few notes about your existing rule:
RewriteCond %{REQUEST_URI} ^/foo$ RewriteCond %{QUERY_STRING} ^query=[a-zA-Z0-9\s]*$ RewriteRule (.*) /foo?%{QUERY_STRING}#anchor [NC,NE,R=302,L,END]
There's no need to use the L
and END
flags together. The L
flag stops the current round of processing and the END
flag stops all further processing by the rewrite engine. However, when used together with the R
flag they behave exactly the same - all further processing is stopped regardless of whether you use L
or END
flag.
query=[a-zA-Z0-9\s]*$
- You've used the \s
(whitespace) shorthand character class - this is superfluous as it will never match here. (Can your query string value actually contain spaces?) The QUERY_STRING
server variable is %-encoded, so there is never a literal space. Any spaces in the requested query string will either be URL encoded as %20
or +
.
The NC
(nocase
flag) on the RewriteRule
directive is superfluous since you are matching "everything" anyway (ie. .*
). I'd wager this is entirely superfluous anyway, since you are not using the NC
flag on the preceding condition where it would be required - if at all.
(.*)
- in the rule as posted there is no need for the parenthesised subpattern (capturing group), since the backreference is not being used anywhere.
RewriteCond %{REQUEST_URI} ^/foo$
- there's no need for this condition as the URL-path can be performed more efficiently in the RewriteRule
pattern.
Upvotes: 1
Reputation: 133680
With your shown samples, could you please try following. Please make sure to clear your browser cache before testing your URLs.
RewriteEngine ON
RewriteCond %{THE_REQUEST} \s/([\w-]+\?query=\d+)\s [NC]
RewriteRule ^ %1#anchor [L,R,NE]
Upvotes: 2