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.