Apache redirect to same path but with a # fragment

I'd like to append a #fragment for the client to read on certain URLs (and used by an SPA).

<IfModule mod_rewrite.c>
 RewriteEngine On
 RewriteBase /
 RewriteRule ^foo/? /foo#bar [QSA,NE,L,R=301]
</IfModule>

However, since #bar is a fragment in the URL above, it seems to get stripped out and cause a redirect loop. I've also tried escaping the hash like RewriteRule ^foo/? /foo\#bar.

Is there some way of limiting that RewriteRule to just one redirect?

  • I'm writing this to an .htaccess file in the target directory. The webserver is httpd -v Server version: Apache/2.4.39 (centos)

Solution 1:

I've also tried escaping the hash like ...

The problem is not the redirect response. /foo#bar is being correctly sent back to the client in the Location: header (the NE flag helps here by preventing the # being URL-encoded in the response).

The problem is that the browser does not send the fragment identifier back to the server on the redirected request (as @Gerald stated, "[Fragments] are never transmitted to the server"). So, the server repeatedly sees /foo, hence the redirect loop. There is nothing you can do about the missing fragment identifier.

From a server perspective, you would need to change the URL in some other way, perhaps by appending a query string parameter. For example:

RewriteCond %{QUERY_STRING} !^redirect
RewriteRule ^foo/? /foo?redirect=1#bar [QSA,NE,R,L]

The above appends a redirect=1 URL parameter to the redirect response and the condition makes sure that this parameter is not present before making the redirect.

However, appending a URL parameter is probably not desirable.

Since this is only for use by the client in an SPA, you should instead be using the JavaScript History API and replaceState() (or possibly pushState()) method(s) to append the #bar fragment identifier to the URL and trigger a client-side response. No server-side redirect is required.

Solution 2:

You can't. Fragments are only handled by the browser. They are never transmitted to the server.