leliflute
leliflute

Reputation: 33

Apache mod_rewrite adding anchor to query string

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

Answers (2)

MrWhite
MrWhite

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

RavinderSingh13
RavinderSingh13

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

Related Questions