Search code examples
.htaccesshttp-redirectmod-rewriteurl-rewritingmod-alias

RewriteRule and RedirectPermanent conflit (adds query string)


All of my RedirectPermanent rules add a query string to the URL. That unwanted query match the redirected rough URL redefine by RewriteRule as followed :

RewriteRule ^page-([0-9]+)-(.*)$ index.php?page=page&id=$1 [L]

This rule works just fine to create that kind of URL :

https://example.com/page-320-enfants

The 301 redirections are defined as followed :

RedirectPermanent /page-320-enfants /page-2028-pour-les-invitees

Problem : this adds a query string to the newly created url :

https://example.com/page-2028-pour-les-invitees?page=page&id=320

I tried to use RewriteRule (old URL to new URL) instead of RedirectPermanent as recommanded in old questions but it has the exact same effect.

Am I missing something?

UPDATE :

As adviced, I tried to use RewriteRule placed before the common rule itself :

Options +FollowSymlinks
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]

# Redirect Permanent #
RewriteRule ^page-2028-pour-les-invitees$ page-320-enfants [R=301,L]

# Common rules #
...
RewriteRule ^page-([0-9]+)-(.*)$ index.php?page=page&id=$1 [L]
...

This attempt does not trigger at all. Could the problem be in the syntax ?


Solution

  • Yes, the RedirectPermanent (mod_alias) directive will add the query string from the earlier rewrite. The RewriteRule (mod_rewrite) directive is processed first, despite the apparent order of the directives, so internally rewrites the request to index.php?page=page&id=320. The RedirectPermanent directive is processed later, but looks at the originally requested URL-path only (not the rewritten URL) so triggers a redirect, but the new query string from the internal rewrite is then appended (any query string on the original request would otherwise be appended).

    If you are already using mod_rewrite for internal rewrites (and possibly other redirects) then you need to use mod_rewrite throughout to avoid such conflicts.

    I tried to use RewriteRule (old URL to new URL) instead of RedirectPermanent as recommanded in old questions but it has the exact same effect.

    That sounds like you are seeing a cached response from the earlier RedirectPermanent directive (301s are cached persistently by the browser). If the correct RewriteRule is placed before the above rewrite it would work as intended. If you placed it after then it wouldn't do anything since the URL-path will not match.

    (From comments)

     RewriteRule /page-320-enfants /page-2028-pour-les-invitees [R=301,L]
    

    This rule seems to be in the right place (before the internal rewrite), however, the RewriteRule pattern (1st argument) is incorrect and will not match the requested URL, so the rule does nothing.

    The RewriteRule pattern (a regex) matches against the URL-path after the directory-prefix (the file-path to the .htaccess file) has been removed. The directory-prefix always ends with a slash, so the URL-path that is matched never starts with a slash. So this rule should be written like this instead:

    RewriteRule ^page-320-enfants$ /page-2028-pour-les-invitees [R=301,L]
    

    To redirect from /page-320-enfants to /page-2028-pour-les-invitees

    UPDATE:

    (From updated question)

    RewriteRule ^page-2028-pour-les-invitees$ page-320-enfants [R=301,L]
    

    Ok, you've removed the slash prefix, however, you seem to have switched the from/to and have omitted the necessary slash prefix on the substitution string (2nd argument)!?

    Assuming you want to redirect from /page-320-enfants then this should appear on the left (first argument).

    The issue with no slash prefix on the substitution string (and no RewriteBase directive) is that the directory-prefix will be added back and expose the server's file-path in the external redirect - in other words, the redirect would be malformed (if it occurred at all).