IIS Rewrite for single query string to SEO version - redirect

I am trying for hours to get the following IIS rewrite to work:
Incoming URL:
https://example.com/services/control/status?Id=SO1234567
Expected output:
https://example.com/orders/detail/SO1234567
IIS Rewrite Rule:
<rule name="Custom rewrite rule" patternSyntax="ExactMatch" stopProcessing="true">
<match url="^services/control/status\?Id=(SO|so){1}([0-9]*)" />
<action type="Rewrite" url="/orders/detail/{R:0}" appendQueryString="false" logRewrittenUrl="true" />
</rule>
Additional information:
I am running a single web site in IIS.
1 web applications for an API under this web site.
Angular files within the web site.
Angular rules:
<rule name="Angular Routes" stopProcessing="false">
<match url=".*" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
Complete Rewrite section:
<rewrite>
<rules>
<clear />
<rule name="Angular Routes" stopProcessing="false">
<match url=".*" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
<add input="{REQUEST_URI}" pattern="^/(marketplace)" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
<rule name="Custom rewrite rule" patternSyntax="ExactMatch" stopProcessing="true">
<match url="^services/control/status\?Id=(SO|so){1}([0-9]*)" />
<action type="Rewrite" url="/orders/detail/{R:0}" appendQueryString="false" logRewrittenUrl="true" />
</rule>
</rule>
</rules>
</rewrite>

As far as I know, the url pattern will not match the query string. If you want to get the query string value, you should use rewrite condition.
Details, you could refer to below rule:
<rule name="QueryStringRue" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{QUERY_STRING}" pattern="^Id=([0-9a-zA-Z]*)" />
</conditions>
<action type="Redirect" url="https://example.com/orders/detail/{C:0}" />
</rule>

Related

IIS rewrite rule with HTTP status code 301

I need to write a IIS rewrite rule which matches the following condition
example.com
www.example.com
http://www.example.com
https://www.example.com
http://example.com
https://example.com
this all should redirect to https://www.example.com/somepage/
The condition is that from SEO point of view only one 301 redirection should be identified. Any pointer is appreciated
Following redirection were tried works but leads to two hops instead of one
<rule name="no path" enabled="true" patternSyntax="ECMAScript" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{REQUEST_URI}" pattern="^\/?$" ignoreCacom="true" />
<add input="{HTTP_HOST}" pattern="^(www.)?example.com$" ignoreCacom="true" />
</conditions>
<action type="Redirect" url="https://www.example.com/somepage" redirectType="Permanent" />
</rule>
<rule name="with path and http" enabled="true" patternSyntax="ECMAScript" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{PATH_INFO}" pattern="\/somepage" negate="true" ignoreCacom="true" />
<add input="{REQUEST_URI}" pattern="^\/.+$" ignoreCacom="true" />
<add input="{HTTP_HOST}" pattern="^(www.)?example.com$" ignoreCacom="true" />
<add input="{HTTPS}" pattern="^OFF$" />
</conditions>
<action type="Redirect" url="https://www.example.com{REQUEST_URI}" redirectType="Permanent" />
</rule>
<rule name="with path and https" enabled="true" patternSyntax="ECMAScript" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{PATH_INFO}" pattern="\/somepage" negate="true" ignoreCacom="true" />
<add input="{REQUEST_URI}" pattern="^\/.+$" ignoreCacom="true" />
<add input="{HTTP_HOST}" pattern="^example.com$" ignoreCacom="true" />
<add input="{HTTPS}" pattern="^ON$" />
</conditions>
<action type="Redirect" url="https://www.example.com{REQUEST_URI}" redirectType="Permanent" />
</rule>
<rule name="with somepage, no www" enabled="true" patternSyntax="ECMAScript" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{PATH_INFO}" pattern="\/somepage" ignoreCacom="true" />
<add input="{HTTP_HOST}" pattern="^example.com$" ignoreCacom="true" />
</conditions>
<action type="Redirect" url="https://www.example.com{REQUEST_URI}" redirectType="Permanent" />
</rule>
<rule name="with somepage and https, no www" enabled="true" patternSyntax="ECMAScript" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{PATH_INFO}" pattern="\/somepage" ignoreCacom="true" />
<add input="{HTTP_HOST}" pattern="^www.example.com$" ignoreCacom="true" />
<add input="{HTTPS}" pattern="^OFF$" />
</conditions>
<action type="Redirect" url="https://www.example.com{REQUEST_URI}" redirectType="Permanent" />
</rule>
enter code here
Are these rules achieve your requirement?
With this rule order. http(s)://(www.)example.com/a.aspx with path will be redirected to https://www.example.com/a.aspx
https://www.example.com/a.aspx will not be redirected to avoid infinite redirection loop.
http(s)://(www.)example.com/ will be redirected to https://www.example.com/somepage.
Since it is impossible to merge everything into a rule. We need at least 3 rule to achieve this.
<rule name="https://www.example.com">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{REQUEST_URI}" pattern="^/.+$" />
<add input="{HTTP_HOST}" pattern="www.example.com" />
<add input="{HTTPS}" pattern="^on$" />
</conditions>
<action type="None" />
</rule>
<rule name="no path" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{URL}" pattern="^(/)?$" />
<add input="{HTTP_HOST}" pattern="^(www\.)?example.com$" />
</conditions>
<action type="Redirect" url="https://www.example.com/somepage/" />
</rule>
<rule name="with path" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{REQUEST_URI}" pattern="^/.+$" />
<add input="{HTTP_HOST}" pattern="^(www\.)?example.com$" />
<add input="{REQUEST_URI}" pattern="^/somepage" negate="true" />
</conditions>
<action type="Redirect" url="https://wwww.example.com{REQUEST_URI}" />
</rule>

IIS RewriteMaps to new URL including WWW and HTTPS

I have the following Rule in my RewriteRules
<rule name="New URL redirects">
<match url=".*"/>
<conditions>
<add input="{OldUrls:{REQUEST_URI}}" pattern="(.+)"/>
</conditions>
<action type="Redirect" url="{C:1}" appendQueryString="false"/>
</rule>
in my RewriteMaps i have the following
<rewriteMap name="OldUrls">
<add key = "/SomeOldUrl" value = "/New/ShinyUrl" />
</rewriteMap>
I want to make sure that the new url is using www and https as part of the redirect, how do i add all of this into one rule?
You could try below rule:
<rule name="Force WWW and SSL" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_HOST}" pattern="^[^www]" />
<add input="{HTTPS}" pattern="off" />
<add input="{HTTPS}" pattern="www.sample1.com" negate="true" />
<add input="{OldUrls:{REQUEST_URI}}" pattern="(.+)" />
</conditions>
<action type="Redirect" url="https://www.sample1.com/{C:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
<rewriteMap name="OldUrls">
<add key="/s2" value="/s3" />
</rewriteMap>
</rewriteMaps>

IIS Rewrite / Redirect Rules Query

The rule below does the following:
- http://www.example.com -> https://example.com
etc
- https://example.com/contacts.html -> . https://example.com/contacts
So (all requests to HTTPS, and all www -> (non)www) + hides .HTML extensions.
I would like to add the ability to remove the following issue:
https://example.com/Home.html -> https://example.com/Home
But for the specific case of /Home I would prefer it displays /
Any help would be greatly appreciated..
Rule below:
<rewrite>
<rules>
<rule name="Force non-WWW and SSL" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAny">
<add input="{HTTP_HOST}" pattern="^(www\.)(.*)$" />
<add input="{HTTPS}" pattern="off" />
</conditions>
<action type="Redirect" url="https://example.com/{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
<rule name="Redirect .html extension" stopProcessing="false">
<match url="^(.*)\.html$" ignoreCase="true" />
<conditions logicalGrouping="MatchAny">
<add input="{URL}" pattern="(.*)\.html$" ignoreCase="false" />
</conditions>
<action type="Redirect" url="{R:1}" redirectType="Permanent" />
</rule>
<rule name="hide .html extension" stopProcessing="true">
<match url="^(.*)$" ignoreCase="true" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_FILENAME}.html" matchType="IsFile" />
</conditions>
<action type="Rewrite" url="{R:0}.html" />
</rule>
</rules>
</rewrite>
I made some change in your rule to prevent rewrite for /Home and /. Then created two rules to handle request to /Home.html.
It works fine on my side and should achieve your requirement.
<rewrite>
<rules>
<rule name="Force non-WWW and SSL" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAny">
<add input="{HTTP_HOST}" pattern="^(www\.)(.*)$" />
<add input="{HTTPS}" pattern="off" />
</conditions>
<action type="Redirect" url="https://example.com/{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
<rule name="Redirect .html extension" enabled="true" stopProcessing="true">
<match url="^(.*)\.html$" ignoreCase="true" />
<conditions logicalGrouping="MatchAll">
<add input="{URL}" pattern="(.*)\.html$" ignoreCase="false" />
<add input="{URL}" pattern="^/Home.html$" negate="true" />
</conditions>
<action type="Redirect" url="{R:1}" redirectType="Permanent" />
</rule>
<rule name="hide .html extension" enabled="true" stopProcessing="true">
<match url="^(.*)$" ignoreCase="true" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_FILENAME}.html" matchType="IsFile" />
<add input="{URL}" pattern="^/$" negate="true" />
<add input="{URL}" pattern="^/Home$" negate="true" />
</conditions>
<action type="Rewrite" url="{R:0}.html" />
</rule>
<rule name="redirect /Home" enabled="true" stopProcessing="true">
<match url="^Home.html$" />
<action type="Redirect" url="/" />
</rule>
<rule name="rewrite Home" stopProcessing="true">
<match url="^$" />
<action type="Rewrite" url="/Home.html" />
</rule>
</rules>
</rewrite>

Two redirections instead of one for Lower Case

When I add the following rule to the redirection file:
<rule name="To Lowercase" enabled="true" stopProcessing="true">
<match url=".*[A-Z].*" ignoreCase="false" />
<conditions>
<add input="{REQUEST_URI}" pattern="^/Images/" negate="true" />
<add input="{REQUEST_METHOD}" pattern="GET" ignoreCase="true" />
</conditions>
<action type="Redirect" url="{ToLower:{R:0}}" redirectType="Permanent" />
</rule>
<rule name="Redirect to WWW">
<match url=".*" />
<conditions>
<add input="{HTTP_HOST}" pattern="^foo.com$" />
</conditions>
<action type="Redirect" url="http://www.foo.com/{R:0}" redirectType="Permanent" />
</rule>
And attempt to open webiste "Foo.com" watching network behaviour I can see that it's first redirected (301) from "https://Foo.com" to "http://foo.com" and then from "http://foo.com" back to "https://foo.com" with status 302.
Is there a way to modify this rule to make just one redirection?
Based on your answers in comments, you can just simply specify the domain name in your rules to avoid multiple redirects. For example:
<rule name="To Lowercase" enabled="true" stopProcessing="true">
<match url=".*[A-Z].*" ignoreCase="false" />
<conditions>
<add input="{REQUEST_URI}" pattern="^/Images/" negate="true" />
<add input="{REQUEST_METHOD}" pattern="GET" ignoreCase="true" />
</conditions>
<action type="Redirect" url="https://www.foo.com/{ToLower:{R:0}}" redirectType="Permanent" />
</rule>
<rule name="Redirect to WWW">
<match url=".*" />
<conditions>
<add input="{HTTP_HOST}" pattern="^foo.com$" />
</conditions>
<action type="Redirect" url="https://www.foo.com/{R:0}" redirectType="Permanent" />
</rule>

In IIS, how can I forward all my URLs to a non-www, https, and no file extension without having too many redirects

I have gone through many similar questions in Stack Overflow, but I have not been able to find one that helps me to have all three of these re-direct rules work together.
I am trying to forward all of my URLs to this format:
https://example.com/page
I need the https, I don't want the www, and I don't want the html or aspx extensions to be visible. Here is what I have so far. Chrome says that I have too many redirects, how do I consolidate these rules?
<rewrite>
<rules>
<clear />
<rule name="RewriteHTML">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="{R:1}.html" />
</rule>
<rule name="Redirect www to non-www" enabled="true" stopProcessing="true">
<match url="(.*)\.html$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_HOST}" pattern="^example\.com$" negate="true" />
</conditions>
<action type="Redirect" url="http://example.com/{R:1}" redirectType="Permanent"/>
</rule>
<rule name="Redirect to HTTPS" enabled="true" stopProcessing="true">
<match url="(.*)\.html$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTPS}" pattern="^OFF$" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent"/>
</rule>
<rule name="RemoveExtension" stopProcessing="true">
<match url="(.*)\.html$" />
<action type="Redirect" url="{R:1}" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
I finally figured it out after playing around with patterns and rule orders, and the stopProcessing command, etc. No more redirect loops! I actually figured out what I was asking and more.
Removes index.html from root domain
Redirects www to non-www
Removes trailing slashes
Makes the URL always lowercase
Redirects http:// to https://
Enables URL to work without .html extension
Redirects to URL without .html extension
My code:
<rules>
<!-- index.html Redirect -->
<rule name="index.html Redirect" enabled="true">
<match url="^(.*\/)*index\.html$" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_METHOD}" negate="true" pattern="^POST$" />
</conditions>
<action type="Redirect" url="{R:1}" redirectType="Permanent" />
</rule>
<!-- Redirect WWW to non-WWW -->
<rule name="Redirect WWW to non-WWW" enabled="true">
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" pattern="^example\.com$" negate="true" />
</conditions>
<action type="Redirect" url="http://example.com/{R:1}" />
</rule>
<!-- Remove Trailing Slash -->
<rule name="Remove Trailing Slash" enabled="true">
<match url="(.*)/$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Redirect" url="{R:1}" />
</rule>
<!-- Make URL Lower Case -->
<rule name="Make URL Lower Case" enabled="true">
<match url="[A-Z]" ignoreCase="false" />
<action type="Redirect" url="{ToLower:{URL}}" />
</rule>
<!-- Redirect To HTTPS -->
<rule name="Redirect To HTTPS" enabled="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTPS}" pattern="^OFF$" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" />
</rule>
<!-- Redirect To URL With No Extension -->
<rule name="Redirect To URL With No Extension" enabled="true">
<match url="(.*)\.(html)" />
<action type="Redirect" url="{R:1}" />
</rule>
<!-- Rewrite URL For No Extension -->
<rule name="Rewrite URL For No Extension" enabled="true" stopProcessing="false">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="{R:0}.html" />
</rule>
</rules>
Here is what the rules look like in the IIS URL Rewrite module: