URL Rewrite Module In Depth
IIS In Depth
Chapter 6 · URL Rewrite Module In Depth
Chapter 1 drew a deliberate line: this course has no dedicated reverse-proxy chapter, because Application Request Routing (ARR) is a genuinely optional add-on most IIS installations never install. URL Rewrite is a separate module from ARR, extremely commonly installed on its own, and doesn't require proxying anything anywhere — it works entirely within a single IIS installation, rewriting or redirecting requests before a handler ever runs. This chapter goes deep on exactly that standalone use.
Rewrite vs. Redirect: Not the Same Action
These two get used almost interchangeably in casual conversation, but they're genuinely different HTTP-level behaviors, and the module treats them as two distinct action types for exactly that reason:
| Rewrite | Redirect | |
|---|---|---|
| What the client sees | Original URL, unchanged in the address bar | A 301/302 response, browser navigates to the new URL |
| Round trips | One — IIS handles it internally | Two — the client must make a second request |
| Typical use | Friendly URLs mapping to an actual query-string-based page, internal routing | Enforcing HTTPS, canonical hostname, permanently moved content |
Rule Anatomy: Match, Conditions, Action
match url is a regular expression tested against the request's relative URL. {R:1} back-references the first parenthesized capture group from that match — a friendly URL like /product/42 matched against ^product/([0-9]+)$ can rewrite to /product.aspx?id={R:1}, with {R:1} substituting the captured 42. <conditions> adds further tests beyond the URL itself — server variables like {HTTPS}, {HTTP_HOST}, {HTTP_USER_AGENT}, or the query string — evaluated with an implicit logical AND by default (logicalGrouping="MatchAll"), or OR if set explicitly. stopProcessing="true" means: once this rule matches and its action runs, skip every rule listed after it, rather than continuing to test the (already-rewritten) URL against the rest of the rule list.
Rewrite Maps: Lookup Tables Instead of Long Rule Chains
A single rewrite rule referencing a map like {LegacyRedirects:{REQUEST_URI}} replaces what would otherwise be dozens of nearly-identical individual rules, one per legacy URL — genuinely useful after a site restructure with many one-off redirects to preserve. {C:1} here back-references the condition's own capture group, distinct from {R:1}, which always refers to the <match> element's capture instead.
Outbound Rules: Rewriting the Response, Not the Request
Every rule shown so far is an inbound rule — it inspects and rewrites the incoming request before a handler runs. An outbound rule does the reverse: it inspects and modifies the generated response — most commonly, rewriting hardcoded links inside HTML content so they match a rewritten public URL structure rather than the internal one the application actually generated. Outbound rules require enabling response content rewriting explicitly and carry a genuine performance cost, since IIS has to buffer and scan the full response body rather than passing it straight through — worth reaching for only when a real link-rewriting need exists, not by default.
Rewrite pointed at a different URL entirely (url="http://backend-server/{R:1}") is precisely how URL Rewrite gets combined with ARR to build a reverse proxy — but that combination is exactly the capability Chapter 1 named as out of scope for this course. Everything in this chapter rewrites or redirects within the same IIS installation; sending a request to a genuinely different backend server is ARR's job, not covered here.
match url pattern again, IIS re-evaluates the rule against its own rewritten output — and can loop. The module detects this and fails the request with an HTTP 500.50 error rather than actually looping forever, but tracking down which rule caused it requires checking that a rule's rewritten output can never itself satisfy its own match pattern, particularly with broad patterns like (.*).
Hands-On Exercises
Explain, in your own words, the genuine behavioral difference between a Rewrite action and a Redirect action, including what the client sees and how many HTTP round trips each involves.
📄 View solutionA site needs friendly URLs like /article/hello-world to map internally to /article.aspx?slug=hello-world. Write the match pattern and action needed, and explain what {R:1} refers to in your rule.
📄 View solutionExplain why URL Rewrite pointing an action at a different backend server's URL is exactly the capability this course deliberately excludes, per Chapter 1's own scope reasoning, even though the rule syntax itself looks almost identical to a same-server rewrite.
📄 View solutionChapter 6 Quick Reference
- Rewrite — internal only, URL unchanged in the browser, one round trip; Redirect — a real 301/302, browser navigates, two round trips
- Rule anatomy:
<match url>(regex against the relative URL) →<conditions>(server variables, ANDed by default) →<action> {R:1}back-references the match's own capture group;{C:1}back-references a condition's capture group — not interchangeable- Rewrite maps replace many near-duplicate rules with one rule plus a lookup table — ideal for bulk legacy-URL redirects
- Outbound rules rewrite the response body (e.g. links in HTML), not the request — genuinely different from inbound rules and carries a real performance cost
- A rule whose own output matches its own pattern again can loop — IIS fails with 500.50 rather than looping forever
- Combining Rewrite with a different backend server's URL is ARR's reverse-proxy territory — deliberately out of scope here (Chapter 1)