ASP.NET Core 中的 URL 重写中间件URL Rewriting Middleware in ASP.NET Core

作者:Mikael MengistuBy Mikael Mengistu

本文档介绍 URL 重写并说明如何在 ASP.NET Core 应用中使用 URL 重写中间件。This document introduces URL rewriting with instructions on how to use URL Rewriting Middleware in ASP.NET Core apps.

URL 重写是根据一个或多个预定义规则修改请求 URL 的行为。URL rewriting is the act of modifying request URLs based on one or more predefined rules. URL 重写会在资源位置和地址之间创建一个抽象,使位置和地址不紧密相连。URL rewriting creates an abstraction between resource locations and their addresses so that the locations and addresses aren't tightly linked. 在以下几种方案中,URL 重写很有价值:URL rewriting is valuable in several scenarios to:

  • 暂时或永久移动或替换服务器资源,并维护这些资源的稳定定位符。Move or replace server resources temporarily or permanently and maintain stable locators for those resources.
  • 拆分在不同应用或同一应用的不同区域中处理的请求。Split request processing across different apps or across areas of one app.
  • 删除、添加或重新组织传入请求上的 URL 段。Remove, add, or reorganize URL segments on incoming requests.
  • 优化搜索引擎优化 (SEO) 的公共 URL。Optimize public URLs for Search Engine Optimization (SEO).
  • 允许使用友好的公共 URL 来帮助访问者预测请求资源后返回的内容。Permit the use of friendly public URLs to help visitors predict the content returned by requesting a resource.
  • 将不安全请求重定向到安全终结点。Redirect insecure requests to secure endpoints.
  • 防止热链接,外部站点会通过热链接将其他站点的资产链接到其自己的内容,从而利用托管在其他站点上的静态资产。Prevent hotlinking, where an external site uses a hosted static asset on another site by linking the asset into its own content.

备注

URL 重写可能会降低应用的性能。URL rewriting can reduce the performance of an app. 如果可行,应限制规则的数量和复杂度。Where feasible, limit the number and complexity of rules.

查看或下载示例代码如何下载View or download sample code (how to download)

URL 重定向和 URL 重写URL redirect and URL rewrite

URL 重定向和 URL 重写之间的用词差异很细微,但这对于向客户端提供资源具有重要意义 。The difference in wording between URL redirect and URL rewrite is subtle but has important implications for providing resources to clients. ASP.NET Core 的 URL 重写中间件能够满足两者的需求。ASP.NET Core's URL Rewriting Middleware is capable of meeting the need for both.

URL 重定向涉及客户端操作,指示客户端访问与客户端最初请求地址不同的资源。A URL redirect involves a client-side operation, where the client is instructed to access a resource at a different address than the client originally requested. 这需要往返服务器。This requires a round trip to the server. 客户端对资源发出新请求时,返回客户端的重定向 URL 会出现在浏览器地址栏。The redirect URL returned to the client appears in the browser's address bar when the client makes a new request for the resource.

如果 /resource 被重定向到 /different-resource,则服务器作出响应,指示客户端应在 /different-resource 获取资源,所提供的状态代码指示重定向是临时的还是永久的。If /resource is redirected to /different-resource, the server responds that the client should obtain the resource at /different-resource with a status code indicating that the redirect is either temporary or permanent.

WebAPI 服务终结点已暂时从服务器上的版本 1 (v1) 更改为版本 2 (v2)。

将请求重定向到不同 URL 时,通过使用响应指定状态代码来指示重定向是永久还是临时:When redirecting requests to a different URL, indicate whether the redirect is permanent or temporary by specifying the status code with the response:

  • 如果资源有一个新的永久性 URL,并且你希望指示客户端所有将来的资源请求都使用新 URL,则使用“301 (永久移动)”状态代码。The 301 - Moved Permanently status code is used where the resource has a new, permanent URL and you wish to instruct the client that all future requests for the resource should use the new URL. 收到 301 状态代码时,客户端可能会缓存响应并重用这段代码。The client may cache and reuse the response when a 301 status code is received.

  • “302 (找到)”状态代码用于后列情况:重定向操作是临时的或通常会发生变化。The 302 - Found status code is used where the redirection is temporary or generally subject to change. 302 状态代码向客户端指示不存储 URL 并在将来使用。The 302 status code indicates to the client not to store the URL and use it in the future.

有关状态代码的详细信息,请参阅 RFC 2616:状态代码定义For more information on status codes, see RFC 2616: Status Code Definitions.

URL 重写是服务器端操作,它从与客户端请求的资源地址不同的资源地址提供资源。A URL rewrite is a server-side operation that provides a resource from a different resource address than the client requested. 重写 URL 不需要往返服务器。Rewriting a URL doesn't require a round trip to the server. 重写的 URL 不会返回客户端,也不会出现在浏览器地址栏。The rewritten URL isn't returned to the client and doesn't appear in the browser's address bar.

如果 /resource 重写到 /different-resource,服务器会在内部提取并返回 /different-resource 处的资源 。If /resource is rewritten to /different-resource, the server internally fetches and returns the resource at /different-resource.

尽管客户端可能能够检索已重写 URL 处的资源,但是,客户端发出请求并收到响应时,并不知道已重写 URL 处存在的资源。Although the client might be able to retrieve the resource at the rewritten URL, the client isn't informed that the resource exists at the rewritten URL when it makes its request and receives the response.

WebAPI 服务终结点已从服务器上的版本 1 (v1) 更改为版本 2 (v2)。

URL 重写示例应用URL rewriting sample app

可使用示例应用了解 URL 重写中间件的功能。You can explore the features of the URL Rewriting Middleware with the sample app. 该应用程序应用重定向和重写规则,并显示多个方案的重定向或重写的 URL。The app applies redirect and rewrite rules and shows the redirected or rewritten URL for several scenarios.

何时使用 URL 重写中间件When to use URL Rewriting Middleware

如果无法使用以下方法,请使用 URL 重写中间件:Use URL Rewriting Middleware when you're unable to use the following approaches:

此外,如果应用程序在 HTTP.sys 服务器(旧称 WebListener)上托管,请使用中间件。Also, use the middleware when the app is hosted on HTTP.sys server (formerly called WebListener).

使用 IIS、Apache 和 Nginx 中的基于服务器的 URL 重写技术的主要原因:The main reasons to use the server-based URL rewriting technologies in IIS, Apache, and Nginx are:

  • 中间件不支持这些模块的完整功能。The middleware doesn't support the full features of these modules.

    服务器模块的一些功能不适用于 ASP.NET Core 项目,例如 IIS 重写模块的 IsFileIsDirectory 约束。Some of the features of the server modules don't work with ASP.NET Core projects, such as the IsFile and IsDirectory constraints of the IIS Rewrite module. 在这些情况下,请改为使用中间件。In these scenarios, use the middleware instead.

  • 中间件性能与模块性能不匹配。The performance of the middleware probably doesn't match that of the modules.

    基准测试是确定哪种方法会最大程度降低性能或降低的性能是否可忽略不计的唯一方法。Benchmarking is the only way to know for sure which approach degrades performance the most or if degraded performance is negligible.

PackagePackage

URL 重写中间件由 Microsoft.AspNetCore.Rewrite 包提供,该包隐式包含在 ASP.NET Core 应用中。URL Rewriting Middleware is provided by the Microsoft.AspNetCore.Rewrite package, which is implicitly included in ASP.NET Core apps.

扩展和选项Extension and options

通过使用扩展方法为每条重写规则创建 RewriteOptions 类的实例,建立 URL 重写和重写定向规则。Establish URL rewrite and redirect rules by creating an instance of the RewriteOptions class with extension methods for each of your rewrite rules. 按所需的处理顺序链接多个规则。Chain multiple rules in the order that you would like them processed. 使用 UseRewriterRewriteOptions 添加到请求管道时,它会被传递到 URL 重写中间件:The RewriteOptions are passed into the URL Rewriting Middleware as it's added to the request pipeline with UseRewriter:

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

将非 www 重定向到 wwwRedirect non-www to www

三个选项允许应用将非 www 重新定向到 wwwThree options permit the app to redirect non-www requests to www:

URL 重定向URL redirect

使用 AddRedirect 将请求重定向。Use AddRedirect to redirect requests. 第一个参数包含用于匹配传入 URL 路径的正则表达式。The first parameter contains your regex for matching on the path of the incoming URL. 第二个参数是替换字符串。The second parameter is the replacement string. 第三个参数(如有)指定状态代码。The third parameter, if present, specifies the status code. 如不指定状态代码,则状态代码默认为“302 (已找到)”,指示资源暂时移动或替换。If you don't specify the status code, the status code defaults to 302 - Found, which indicates that the resource is temporarily moved or replaced.

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

在启用了开发人员工具的浏览器中,向路径为 /redirect-rule/1234/5678 的示例应用发出请求。In a browser with developer tools enabled, make a request to the sample app with the path /redirect-rule/1234/5678. 正则表达式匹配 redirect-rule/(.*) 上的请求路径,且该路径会被 /redirected/1234/5678 替代。The regex matches the request path on redirect-rule/(.*), and the path is replaced with /redirected/1234/5678. 重定向 URL 以“302 (已找到)”状态代码发回客户端。The redirect URL is sent back to the client with a 302 - Found status code. 浏览器会在浏览器地址栏中出现的重定向 URL 上发出新请求。The browser makes a new request at the redirect URL, which appears in the browser's address bar. 由于示例应用中的规则都不匹配重定向 URL:Since no rules in the sample app match on the redirect URL:

  • 第二个请求从应用程序收到“200 (正常)”响应。The second request receives a 200 - OK response from the app.
  • 响应正文显示了重定向 URL。The body of the response shows the redirect URL.

重定向 URL 时,系统将向服务器进行一次往返。A round trip is made to the server when a URL is redirected.

警告

建立重定向规则时务必小心。Be cautious when establishing redirect rules. 系统会根据应用的每个请求(包括重定向后的请求)对重定向规则进行评估。Redirect rules are evaluated on every request to the app, including after a redirect. 很容易便会意外创建无限重定向循环。It's easy to accidentally create a loop of infinite redirects.

原始请求:/redirect-rule/1234/5678Original Request: /redirect-rule/1234/5678

开发人员工具正跟踪请求和响应的浏览器窗口

括号内的表达式部分称为“捕获组”。The part of the expression contained within parentheses is called a capture group. 表达式的点 (.) 表示匹配任何字符。The dot (.) of the expression means match any character. 星号 (*) 表示零次或多次匹配前面的字符。The asterisk (*) indicates match the preceding character zero or more times. 因此,URL 的最后两个路径段 1234/5678 由捕获组 (.*) 捕获。Therefore, the last two path segments of the URL, 1234/5678, are captured by capture group (.*). 在请求 URL 中提供的位于 redirect-rule/ 之后的任何值均由此单个捕获组捕获。Any value you provide in the request URL after redirect-rule/ is captured by this single capture group.

在替换字符串中,将捕获组注入带有美元符号 ($)、后跟捕获序列号的字符串中。In the replacement string, captured groups are injected into the string with the dollar sign ($) followed by the sequence number of the capture. 获取的第一个捕获组值为 $1,第二个为 $2,并且正则表达式中的其他捕获组值将依次继续排列。The first capture group value is obtained with $1, the second with $2, and they continue in sequence for the capture groups in your regex. 示例应用的重定向规则正则表达式中只有一个捕获组,因此替换字符串中只有一个注入组,即 $1There's only one captured group in the redirect rule regex in the sample app, so there's only one injected group in the replacement string, which is $1. 如果应用此规则,URL 将变为 /redirected/1234/5678When the rule is applied, the URL becomes /redirected/1234/5678.

URL 重定向到安全的终结点URL redirect to a secure endpoint

使用 AddRedirectToHttps 将 HTTP 请求重定向到采用 HTTPS 协议的相同主机和路径。Use AddRedirectToHttps to redirect HTTP requests to the same host and path using the HTTPS protocol. 如不提供状态代码,则中间件默认为“302(已找到)”。If the status code isn't supplied, the middleware defaults to 302 - Found. 如果不提供端口:If the port isn't supplied:

  • 中间件默认为 nullThe middleware defaults to null.
  • 方案更改为 https(HTTPS 协议),客户端访问端口 443 上的资源。The scheme changes to https (HTTPS protocol), and the client accesses the resource on port 443.

下面的示例演示如何将状态代码设置为“301(永久移动)”并将端口更改为 5001。The following example shows how to set the status code to 301 - Moved Permanently and change the port to 5001.

public void Configure(IApplicationBuilder app)
{
    var options = new RewriteOptions()
        .AddRedirectToHttps(301, 5001);

    app.UseRewriter(options);
}

使用 AddRedirectToHttpsPermanent 将不安全的请求重定向到端口 443 上的采用安全 HTTPS 协议的相同主机和路径。Use AddRedirectToHttpsPermanent to redirect insecure requests to the same host and path with secure HTTPS protocol on port 443. 中间件将状态代码设置为“301 (永久移动)”。The middleware sets the status code to 301 - Moved Permanently.

public void Configure(IApplicationBuilder app)
{
    var options = new RewriteOptions()
        .AddRedirectToHttpsPermanent();

    app.UseRewriter(options);
}

备注

当重定向到安全的终结点并且不需要其他重定向规则时,建议使用 HTTPS 重定向中间件。When redirecting to a secure endpoint without the requirement for additional redirect rules, we recommend using HTTPS Redirection Middleware. 有关详细信息,请参阅强制使用 HTTPS主题。For more information, see the Enforce HTTPS topic.

示例应用能够演示如何使用 AddRedirectToHttpsAddRedirectToHttpsPermanentThe sample app is capable of demonstrating how to use AddRedirectToHttps or AddRedirectToHttpsPermanent. 将扩展方法添加到 RewriteOptionsAdd the extension method to the RewriteOptions. 在任何 URL 上向应用发出不安全的请求。Make an insecure request to the app at any URL. 消除自签名证书不受信任的浏览器安全警告,或创建例外以信任证书。Dismiss the browser security warning that the self-signed certificate is untrusted or create an exception to trust the certificate.

使用 AddRedirectToHttps(301, 5001) 的原始请求:http://localhost:5000/secureOriginal Request using AddRedirectToHttps(301, 5001): http://localhost:5000/secure

开发人员工具正跟踪请求和响应的浏览器窗口

使用 AddRedirectToHttpsPermanent 的原始请求:http://localhost:5000/secureOriginal Request using AddRedirectToHttpsPermanent: http://localhost:5000/secure

开发人员工具正跟踪请求和响应的浏览器窗口

URL 重写URL rewrite

使用 AddRewrite 创建重写 URL 的规则。Use AddRewrite to create a rule for rewriting URLs. 第一个参数包含用于匹配传入 URL 路径的正则表达式。The first parameter contains the regex for matching on the incoming URL path. 第二个参数是替换字符串。The second parameter is the replacement string. 第三个参数 skipRemainingRules: {true|false} 指示如果当前规则适用,中间件是否要跳过其他重写规则。The third parameter, skipRemainingRules: {true|false}, indicates to the middleware whether or not to skip additional rewrite rules if the current rule is applied.

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

原始请求:/rewrite-rule/1234/5678Original Request: /rewrite-rule/1234/5678

开发人员工具正跟踪请求和响应的浏览器窗口

表达式开头的脱字号 (^) 意味着匹配从 URL 路径的开头处开始。The carat (^) at the beginning of the expression means that matching starts at the beginning of the URL path.

在前面的重定向规则 redirect-rule/(.*) 的示例中,正则表达式的开头没有脱字号 (^)。In the earlier example with the redirect rule, redirect-rule/(.*), there's no carat (^) at the start of the regex. 因此,路径中 redirect-rule/ 之前的任何字符都可能成功匹配。Therefore, any characters may precede redirect-rule/ in the path for a successful match.

路径Path 匹配Match
/redirect-rule/1234/5678 Yes
/my-cool-redirect-rule/1234/5678 Yes
/anotherredirect-rule/1234/5678 Yes

重写规则 ^rewrite-rule/(\d+)/(\d+) 只能与以 rewrite-rule/ 开头的路径匹配。The rewrite rule, ^rewrite-rule/(\d+)/(\d+), only matches paths if they start with rewrite-rule/. 注意下表中的匹配差异。In the following table, note the difference in matching.

路径Path 匹配Match
/rewrite-rule/1234/5678 Yes
/my-cool-rewrite-rule/1234/5678 No
/anotherrewrite-rule/1234/5678 No

在表达式的 ^rewrite-rule/ 部分之后,有两个捕获组 (\d+)/(\d+)Following the ^rewrite-rule/ portion of the expression, there are two capture groups, (\d+)/(\d+). \d 表示与数字匹配。The \d signifies match a digit (number). 加号 (+) 表示与前面的一个或多个字符匹配。The plus sign (+) means match one or more of the preceding character. 因此,URL 必须包含数字加正斜杠加另一个数字的形式。Therefore, the URL must contain a number followed by a forward-slash followed by another number. 这些捕获组以 $1$2 的形式注入重写 URL 中。These capture groups are injected into the rewritten URL as $1 and $2. 重写规则替换字符串将捕获组放入查询字符串中。The rewrite rule replacement string places the captured groups into the query string. 重写 /rewrite-rule/1234/5678 的请求路径,获取 /rewritten?var1=1234&var2=5678 处的资源。The requested path of /rewrite-rule/1234/5678 is rewritten to obtain the resource at /rewritten?var1=1234&var2=5678. 如果原始请求中存在查询字符串,则重写 URL 时会保留此字符串。If a query string is present on the original request, it's preserved when the URL is rewritten.

无需往返服务器来获取资源。There's no round trip to the server to obtain the resource. 如果资源存在,系统会提取资源并以“200(正常)”状态代码返回给客户端。If the resource exists, it's fetched and returned to the client with a 200 - OK status code. 因为客户端不会被重定向,所以浏览器地址栏中的 URL 不会发生更改。Because the client isn't redirected, the URL in the browser's address bar doesn't change. 客户端无法检测到服务器上发生的 URL 重写操作。Clients can't detect that a URL rewrite operation occurred on the server.

备注

尽可能使用 skipRemainingRules: true,因为匹配规则在计算上很昂贵并且增加了应用响应时间。Use skipRemainingRules: true whenever possible because matching rules is computationally expensive and increases app response time. 对于最快的应用响应:For the fastest app response:

  • 按照从最频繁匹配的规则到最不频繁匹配的规则排列重写规则。Order rewrite rules from the most frequently matched rule to the least frequently matched rule.
  • 如果出现匹配项且无需处理任何其他规则,则跳过剩余规则的处理。Skip the processing of the remaining rules when a match occurs and no additional rule processing is required.

Apache mod_rewriteApache mod_rewrite

使用 AddApacheModRewrite 应用 Apache mod_rewrite 规则。Apply Apache mod_rewrite rules with AddApacheModRewrite. 请确保将规则文件与应用一起部署。Make sure that the rules file is deployed with the app. 有关 mod_rewrite 规则的详细信息和示例,请参阅 Apache mod_rewriteFor more information and examples of mod_rewrite rules, see Apache mod_rewrite.

StreamReader 用于读取 ApacheModRewrite.txt 规则文件中的规则:A StreamReader is used to read the rules from the ApacheModRewrite.txt rules file:

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

示例应用将请求从 /apache-mod-rules-redirect/(.\*) 重定向到 /redirected?id=$1The sample app redirects requests from /apache-mod-rules-redirect/(.\*) to /redirected?id=$1. 响应状态代码为“302 (已找到)”。The response status code is 302 - Found.

# Rewrite path with additional sub directory
RewriteRule ^/apache-mod-rules-redirect/(.*) /redirected?id=$1 [L,R=302]

原始请求:/apache-mod-rules-redirect/1234Original Request: /apache-mod-rules-redirect/1234

开发人员工具正跟踪请求和响应的浏览器窗口

中间件支持下列 Apache mod_rewrite 服务器变量:The middleware supports the following Apache mod_rewrite server variables:

  • CONN_REMOTE_ADDRCONN_REMOTE_ADDR
  • HTTP_ACCEPTHTTP_ACCEPT
  • HTTP_CONNECTIONHTTP_CONNECTION
  • HTTP_COOKIEHTTP_COOKIE
  • HTTP_FORWARDEDHTTP_FORWARDED
  • HTTP_HOSTHTTP_HOST
  • HTTP_REFERERHTTP_REFERER
  • HTTP_USER_AGENTHTTP_USER_AGENT
  • HTTPSHTTPS
  • IPV6IPV6
  • QUERY_STRINGQUERY_STRING
  • REMOTE_ADDRREMOTE_ADDR
  • REMOTE_PORTREMOTE_PORT
  • REQUEST_FILENAMEREQUEST_FILENAME
  • REQUEST_METHODREQUEST_METHOD
  • REQUEST_SCHEMEREQUEST_SCHEME
  • REQUEST_URIREQUEST_URI
  • SCRIPT_FILENAMESCRIPT_FILENAME
  • SERVER_ADDRSERVER_ADDR
  • SERVER_PORTSERVER_PORT
  • SERVER_PROTOCOLSERVER_PROTOCOL
  • TIMETIME
  • TIME_DAYTIME_DAY
  • TIME_HOURTIME_HOUR
  • TIME_MINTIME_MIN
  • TIME_MONTIME_MON
  • TIME_SECTIME_SEC
  • TIME_WDAYTIME_WDAY
  • TIME_YEARTIME_YEAR

IIS URL 重写模块规则IIS URL Rewrite Module rules

若要使用适用于 IIS URL 重写模块的同一规则集,使用 AddIISUrlRewriteTo use the same rule set that applies to the IIS URL Rewrite Module, use AddIISUrlRewrite. 请确保将规则文件与应用一起部署。Make sure that the rules file is deployed with the app. 当在 Windows Server IIS 上运行时,请勿指示中间件使用应用的 web.config 文件。Don't direct the middleware to use the app's web.config file when running on Windows Server IIS. 使用 IIS 时,应将这些规则存储在应用的 web.config 文件之外,以避免与 IIS 重写模块发生冲突。With IIS, these rules should be stored outside of the app's web.config file in order to avoid conflicts with the IIS Rewrite module. 有关 IIS URL 重写模块规则的详细信息和示例,请参阅 Using Url Rewrite Module 2.0(使用 URL 重写模块 2.0)和 URL Rewrite Module Configuration Reference(URL 重写模块配置引用)。For more information and examples of IIS URL Rewrite Module rules, see Using Url Rewrite Module 2.0 and URL Rewrite Module Configuration Reference.

StreamReader 用于读取 IISUrlRewrite.xml 规则文件中的规则:A StreamReader is used to read the rules from the IISUrlRewrite.xml rules file:

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

示例应用将请求从 /iis-rules-rewrite/(.*) 重写为 /rewritten?id=$1The sample app rewrites requests from /iis-rules-rewrite/(.*) to /rewritten?id=$1. 以“200 (正常)”状态代码作为响应发送到客户端。The response is sent to the client with a 200 - OK status code.

<rewrite>
  <rules>
    <rule name="Rewrite segment to id querystring" stopProcessing="true">
      <match url="^iis-rules-rewrite/(.*)$" />
      <action type="Rewrite" url="rewritten?id={R:1}" appendQueryString="false"/>
    </rule>
  </rules>
</rewrite>

原始请求:/iis-rules-rewrite/1234Original Request: /iis-rules-rewrite/1234

开发人员工具正跟踪请求和响应的浏览器窗口

如果有配置了服务器级别规则(可对应用产生不利影响)的活动 IIS 重写模块,则可禁用应用的 IIS 重写模块。If you have an active IIS Rewrite Module with server-level rules configured that would impact your app in undesirable ways, you can disable the IIS Rewrite Module for an app. 有关详细信息,请参阅禁用 IIS 模块For more information, see Disabling IIS modules.

不支持的功能Unsupported features

与 ASP.NET Core 2.x 一同发布的中间件不支持以下 IIS URL 重写模块功能:The middleware released with ASP.NET Core 2.x doesn't support the following IIS URL Rewrite Module features:

  • 出站规则Outbound Rules
  • 自定义服务器变量Custom Server Variables
  • 通配符Wildcards
  • LogRewrittenUrlLogRewrittenUrl

受支持的服务器变量Supported server variables

中间件支持下列 IIS URL 重写模块服务器变量:The middleware supports the following IIS URL Rewrite Module server variables:

  • CONTENT_LENGTHCONTENT_LENGTH
  • CONTENT_TYPECONTENT_TYPE
  • HTTP_ACCEPTHTTP_ACCEPT
  • HTTP_CONNECTIONHTTP_CONNECTION
  • HTTP_COOKIEHTTP_COOKIE
  • HTTP_HOSTHTTP_HOST
  • HTTP_REFERERHTTP_REFERER
  • HTTP_URLHTTP_URL
  • HTTP_USER_AGENTHTTP_USER_AGENT
  • HTTPSHTTPS
  • LOCAL_ADDRLOCAL_ADDR
  • QUERY_STRINGQUERY_STRING
  • REMOTE_ADDRREMOTE_ADDR
  • REMOTE_PORTREMOTE_PORT
  • REQUEST_FILENAMEREQUEST_FILENAME
  • REQUEST_URIREQUEST_URI

备注

也可通过 PhysicalFileProvider 获取 IFileProviderYou can also obtain an IFileProvider via a PhysicalFileProvider. 这种方法可为重写规则文件的位置提供更大的灵活性。This approach may provide greater flexibility for the location of your rewrite rules files. 请确保将重写规则文件部署到所提供路径的服务器中。Make sure that your rewrite rules files are deployed to the server at the path you provide.

PhysicalFileProvider fileProvider = new PhysicalFileProvider(Directory.GetCurrentDirectory());

基于方法的规则Method-based rule

使用 Add 在方法中实现自己的规则逻辑。Use Add to implement your own rule logic in a method. Add 公开 RewriteContext,这使 HttpContext 可用于方法中。Add exposes the RewriteContext, which makes available the HttpContext for use in your method. RewriteContext.Result 决定如何处理其他管道进程。The RewriteContext.Result determines how additional pipeline processing is handled. 将值设置为下表中的 RuleResult 字段之一。Set the value to one of the RuleResult fields described in the following table.

重写上下文结果Rewrite context result 操作Action
RuleResult.ContinueRules(默认值)RuleResult.ContinueRules (default) 继续应用规则。Continue applying rules.
RuleResult.EndResponse 停止应用规则并发送响应。Stop applying rules and send the response.
RuleResult.SkipRemainingRules 停止应用规则并将上下文发送给下一个中间件。Stop applying rules and send the context to the next middleware.
public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

示例应用演示了如何对以 .xml 结尾的路径的请求进行重定向。The sample app demonstrates a method that redirects requests for paths that end with .xml. 如果发出针对 /file.xml 的请求,请求将重定向到 /xmlfiles/file.xmlIf a request is made for /file.xml, the request is redirected to /xmlfiles/file.xml. 状态代码设置为“301 (永久移动)”。The status code is set to 301 - Moved Permanently. 当浏览器发出针对 /xmlfiles/file.xml 的新请求后,静态文件中间件会将文件从 wwwroot / xmlfiles 文件夹提供给客户端 。When the browser makes a new request for /xmlfiles/file.xml, Static File Middleware serves the file to the client from the wwwroot/xmlfiles folder. 对于重定向,请显式设置响应的状态代码。For a redirect, explicitly set the status code of the response. 否则,将会返回“200 (正常)”状态代码,且客户端上不会发生重写。Otherwise, a 200 - OK status code is returned, and the redirect doesn't occur on the client.

RewriteRules.cs:RewriteRules.cs:

public static void RedirectXmlFileRequests(RewriteContext context)
{
    var request = context.HttpContext.Request;

    // Because the client is redirecting back to the same app, stop 
    // processing if the request has already been redirected.
    if (request.Path.StartsWithSegments(new PathString("/xmlfiles")))
    {
        return;
    }

    if (request.Path.Value.EndsWith(".xml", StringComparison.OrdinalIgnoreCase))
    {
        var response = context.HttpContext.Response;
        response.StatusCode = StatusCodes.Status301MovedPermanently;
        context.Result = RuleResult.EndResponse;
        response.Headers[HeaderNames.Location] = 
            "/xmlfiles" + request.Path + request.QueryString;
    }
}

此方法还可以重写请求。This approach can also rewrite requests. 示例应用演示了如何重写任何文本文件请求的路径以从 wwwroot 文件夹中提供 file.txt 文本文件 。The sample app demonstrates rewriting the path for any text file request to serve the file.txt text file from the wwwroot folder. 静态文件中间件基于更新的请求路径来提供文件:Static File Middleware serves the file based on the updated request path:

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

RewriteRules.cs:RewriteRules.cs:

public static void RewriteTextFileRequests(RewriteContext context)
{
    var request = context.HttpContext.Request;

    if (request.Path.Value.EndsWith(".txt", StringComparison.OrdinalIgnoreCase))
    {
        context.Result = RuleResult.SkipRemainingRules;
        request.Path = "/file.txt";
    }
}

基于 IRule 的规则IRule-based rule

使用 Add 在实现 IRule 接口的类中使用规则逻辑。Use Add to use rule logic in a class that implements the IRule interface. 与使用基于方法的规则方法相比,IRule 提供了更大的灵活性。IRule provides greater flexibility over using the method-based rule approach. 实现类可能包含构造函数,可在其中传入 ApplyRule 方法的参数。Your implementation class may include a constructor that allows you can pass in parameters for the ApplyRule method.

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

检查示例应用中 extensionnewPath 的参数值是否符合多个条件。The values of the parameters in the sample app for the extension and the newPath are checked to meet several conditions. extension 须包含一个值,并且该值必须是 .png、.jpg 或 .gif 。The extension must contain a value, and the value must be .png, .jpg, or .gif. 如果 newPath 无效,则会引发 ArgumentExceptionIf the newPath isn't valid, an ArgumentException is thrown. 如果发出针对 image.png 的请求,请求将重定向到 /png-images/image.pngIf a request is made for image.png, the request is redirected to /png-images/image.png. 如果发出针对 image.png 的请求,请求将重定向到 /jpg-images/image.jpgIf a request is made for image.jpg, the request is redirected to /jpg-images/image.jpg. 状态代码设置为“301 (永久移动)”,context.Result 设置为停止处理规则并发送响应。The status code is set to 301 - Moved Permanently, and the context.Result is set to stop processing rules and send the response.

public class RedirectImageRequests : IRule
{
    private readonly string _extension;
    private readonly PathString _newPath;

    public RedirectImageRequests(string extension, string newPath)
    {
        if (string.IsNullOrEmpty(extension))
        {
            throw new ArgumentException(nameof(extension));
        }

        if (!Regex.IsMatch(extension, @"^\.(png|jpg|gif)$"))
        {
            throw new ArgumentException("Invalid extension", nameof(extension));
        }

        if (!Regex.IsMatch(newPath, @"(/[A-Za-z0-9]+)+?"))
        {
            throw new ArgumentException("Invalid path", nameof(newPath));
        }

        _extension = extension;
        _newPath = new PathString(newPath);
    }

    public void ApplyRule(RewriteContext context)
    {
        var request = context.HttpContext.Request;

        // Because we're redirecting back to the same app, stop 
        // processing if the request has already been redirected
        if (request.Path.StartsWithSegments(new PathString(_newPath)))
        {
            return;
        }

        if (request.Path.Value.EndsWith(_extension, StringComparison.OrdinalIgnoreCase))
        {
            var response = context.HttpContext.Response;
            response.StatusCode = StatusCodes.Status301MovedPermanently;
            context.Result = RuleResult.EndResponse;
            response.Headers[HeaderNames.Location] = 
                _newPath + request.Path + request.QueryString;
        }
    }
}

原始请求:/image.pngOriginal Request: /image.png

开发人员工具正跟踪 image.png 的请求和响应的浏览器窗口

原始请求:/image.jpgOriginal Request: /image.jpg

开发人员工具正跟踪 image.jpg 的请求和响应的浏览器窗口

正则表达式示例Regex examples

目标Goal 正则表达式字符串和Regex String &
匹配示例Match Example
替换字符串和Replacement String &
输出示例Output Example
将路径重写为查询字符串Rewrite path into querystring ^path/(.*)/(.*)
/path/abc/123
path?var1=$1&var2=$2
/path?var1=abc&var2=123
去掉尾部反斜杠Strip trailing slash (.*)/$
/path/
$1
/path
强制添加尾部反斜杠Enforce trailing slash (.*[^/])$
/path
$1/
/path/
避免重写特定请求Avoid rewriting specific requests ^(.*)(?<!\.axd)$^(?!.*\.axd$)(.*)$^(.*)(?<!\.axd)$ or ^(?!.*\.axd$)(.*)$
正确:/resource.htmYes: /resource.htm
错误:/resource.axdNo: /resource.axd
rewritten/$1
/rewritten/resource.htm
/resource.axd
重新排列 URL 段Rearrange URL segments path/(.*)/(.*)/(.*)
path/1/2/3
path/$3/$2/$1
path/3/2/1
替换 URL 段Replace a URL segment ^(.*)/segment2/(.*)
/segment1/segment2/segment3
$1/replaced/$2
/segment1/replaced/segment3

本文档介绍 URL 重写并说明如何在 ASP.NET Core 应用中使用 URL 重写中间件。This document introduces URL rewriting with instructions on how to use URL Rewriting Middleware in ASP.NET Core apps.

URL 重写是根据一个或多个预定义规则修改请求 URL 的行为。URL rewriting is the act of modifying request URLs based on one or more predefined rules. URL 重写会在资源位置和地址之间创建一个抽象,使位置和地址不紧密相连。URL rewriting creates an abstraction between resource locations and their addresses so that the locations and addresses aren't tightly linked. 在以下几种方案中,URL 重写很有价值:URL rewriting is valuable in several scenarios to:

  • 暂时或永久移动或替换服务器资源,并维护这些资源的稳定定位符。Move or replace server resources temporarily or permanently and maintain stable locators for those resources.
  • 拆分在不同应用或同一应用的不同区域中处理的请求。Split request processing across different apps or across areas of one app.
  • 删除、添加或重新组织传入请求上的 URL 段。Remove, add, or reorganize URL segments on incoming requests.
  • 优化搜索引擎优化 (SEO) 的公共 URL。Optimize public URLs for Search Engine Optimization (SEO).
  • 允许使用友好的公共 URL 来帮助访问者预测请求资源后返回的内容。Permit the use of friendly public URLs to help visitors predict the content returned by requesting a resource.
  • 将不安全请求重定向到安全终结点。Redirect insecure requests to secure endpoints.
  • 防止热链接,外部站点会通过热链接将其他站点的资产链接到其自己的内容,从而利用托管在其他站点上的静态资产。Prevent hotlinking, where an external site uses a hosted static asset on another site by linking the asset into its own content.

备注

URL 重写可能会降低应用的性能。URL rewriting can reduce the performance of an app. 如果可行,应限制规则的数量和复杂度。Where feasible, limit the number and complexity of rules.

查看或下载示例代码如何下载View or download sample code (how to download)

URL 重定向和 URL 重写URL redirect and URL rewrite

URL 重定向和 URL 重写之间的用词差异很细微,但这对于向客户端提供资源具有重要意义 。The difference in wording between URL redirect and URL rewrite is subtle but has important implications for providing resources to clients. ASP.NET Core 的 URL 重写中间件能够满足两者的需求。ASP.NET Core's URL Rewriting Middleware is capable of meeting the need for both.

URL 重定向涉及客户端操作,指示客户端访问与客户端最初请求地址不同的资源。A URL redirect involves a client-side operation, where the client is instructed to access a resource at a different address than the client originally requested. 这需要往返服务器。This requires a round trip to the server. 客户端对资源发出新请求时,返回客户端的重定向 URL 会出现在浏览器地址栏。The redirect URL returned to the client appears in the browser's address bar when the client makes a new request for the resource.

如果 /resource 被重定向到 /different-resource,则服务器作出响应,指示客户端应在 /different-resource 获取资源,所提供的状态代码指示重定向是临时的还是永久的。If /resource is redirected to /different-resource, the server responds that the client should obtain the resource at /different-resource with a status code indicating that the redirect is either temporary or permanent.

WebAPI 服务终结点已暂时从服务器上的版本 1 (v1) 更改为版本 2 (v2)。

将请求重定向到不同 URL 时,通过使用响应指定状态代码来指示重定向是永久还是临时:When redirecting requests to a different URL, indicate whether the redirect is permanent or temporary by specifying the status code with the response:

  • 如果资源有一个新的永久性 URL,并且你希望指示客户端所有将来的资源请求都使用新 URL,则使用“301 (永久移动)”状态代码。The 301 - Moved Permanently status code is used where the resource has a new, permanent URL and you wish to instruct the client that all future requests for the resource should use the new URL. 收到 301 状态代码时,客户端可能会缓存响应并重用这段代码。The client may cache and reuse the response when a 301 status code is received.

  • “302 (找到)”状态代码用于后列情况:重定向操作是临时的或通常会发生变化。The 302 - Found status code is used where the redirection is temporary or generally subject to change. 302 状态代码向客户端指示不存储 URL 并在将来使用。The 302 status code indicates to the client not to store the URL and use it in the future.

有关状态代码的详细信息,请参阅 RFC 2616:状态代码定义For more information on status codes, see RFC 2616: Status Code Definitions.

URL 重写是服务器端操作,它从与客户端请求的资源地址不同的资源地址提供资源。A URL rewrite is a server-side operation that provides a resource from a different resource address than the client requested. 重写 URL 不需要往返服务器。Rewriting a URL doesn't require a round trip to the server. 重写的 URL 不会返回客户端,也不会出现在浏览器地址栏。The rewritten URL isn't returned to the client and doesn't appear in the browser's address bar.

如果 /resource 重写到 /different-resource,服务器会在内部提取并返回 /different-resource 处的资源 。If /resource is rewritten to /different-resource, the server internally fetches and returns the resource at /different-resource.

尽管客户端可能能够检索已重写 URL 处的资源,但是,客户端发出请求并收到响应时,并不知道已重写 URL 处存在的资源。Although the client might be able to retrieve the resource at the rewritten URL, the client isn't informed that the resource exists at the rewritten URL when it makes its request and receives the response.

WebAPI 服务终结点已从服务器上的版本 1 (v1) 更改为版本 2 (v2)。

URL 重写示例应用URL rewriting sample app

可使用示例应用了解 URL 重写中间件的功能。You can explore the features of the URL Rewriting Middleware with the sample app. 该应用程序应用重定向和重写规则,并显示多个方案的重定向或重写的 URL。The app applies redirect and rewrite rules and shows the redirected or rewritten URL for several scenarios.

何时使用 URL 重写中间件When to use URL Rewriting Middleware

如果无法使用以下方法,请使用 URL 重写中间件:Use URL Rewriting Middleware when you're unable to use the following approaches:

此外,如果应用程序在 HTTP.sys 服务器(旧称 WebListener)上托管,请使用中间件。Also, use the middleware when the app is hosted on HTTP.sys server (formerly called WebListener).

使用 IIS、Apache 和 Nginx 中的基于服务器的 URL 重写技术的主要原因:The main reasons to use the server-based URL rewriting technologies in IIS, Apache, and Nginx are:

  • 中间件不支持这些模块的完整功能。The middleware doesn't support the full features of these modules.

    服务器模块的一些功能不适用于 ASP.NET Core 项目,例如 IIS 重写模块的 IsFileIsDirectory 约束。Some of the features of the server modules don't work with ASP.NET Core projects, such as the IsFile and IsDirectory constraints of the IIS Rewrite module. 在这些情况下,请改为使用中间件。In these scenarios, use the middleware instead.

  • 中间件性能与模块性能不匹配。The performance of the middleware probably doesn't match that of the modules.

    基准测试是确定哪种方法会最大程度降低性能或降低的性能是否可忽略不计的唯一方法。Benchmarking is the only way to know for sure which approach degrades performance the most or if degraded performance is negligible.

PackagePackage

要在项目中包含中间件,请在项目文件中添加对 Microsoft.AspNetCore.App 元数据包的包引用,该文件包含 Microsoft.AspNetCore.Rewrite 包。To include the middleware in your project, add a package reference to the Microsoft.AspNetCore.App metapackage in the project file, which contains the Microsoft.AspNetCore.Rewrite package.

不使用 Microsoft.AspNetCore.App 元包时,向 Microsoft.AspNetCore.Rewrite 包添加项目引用。When not using the Microsoft.AspNetCore.App metapackage, add a project reference to the Microsoft.AspNetCore.Rewrite package.

扩展和选项Extension and options

通过使用扩展方法为每条重写规则创建 RewriteOptions 类的实例,建立 URL 重写和重写定向规则。Establish URL rewrite and redirect rules by creating an instance of the RewriteOptions class with extension methods for each of your rewrite rules. 按所需的处理顺序链接多个规则。Chain multiple rules in the order that you would like them processed. 使用 UseRewriterRewriteOptions 添加到请求管道时,它会被传递到 URL 重写中间件:The RewriteOptions are passed into the URL Rewriting Middleware as it's added to the request pipeline with UseRewriter:

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

将非 www 重定向到 wwwRedirect non-www to www

三个选项允许应用将非 www 重新定向到 wwwThree options permit the app to redirect non-www requests to www:

URL 重定向URL redirect

使用 AddRedirect 将请求重定向。Use AddRedirect to redirect requests. 第一个参数包含用于匹配传入 URL 路径的正则表达式。The first parameter contains your regex for matching on the path of the incoming URL. 第二个参数是替换字符串。The second parameter is the replacement string. 第三个参数(如有)指定状态代码。The third parameter, if present, specifies the status code. 如不指定状态代码,则状态代码默认为“302 (已找到)”,指示资源暂时移动或替换。If you don't specify the status code, the status code defaults to 302 - Found, which indicates that the resource is temporarily moved or replaced.

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

在启用了开发人员工具的浏览器中,向路径为 /redirect-rule/1234/5678 的示例应用发出请求。In a browser with developer tools enabled, make a request to the sample app with the path /redirect-rule/1234/5678. 正则表达式匹配 redirect-rule/(.*) 上的请求路径,且该路径会被 /redirected/1234/5678 替代。The regex matches the request path on redirect-rule/(.*), and the path is replaced with /redirected/1234/5678. 重定向 URL 以“302 (已找到)”状态代码发回客户端。The redirect URL is sent back to the client with a 302 - Found status code. 浏览器会在浏览器地址栏中出现的重定向 URL 上发出新请求。The browser makes a new request at the redirect URL, which appears in the browser's address bar. 由于示例应用中的规则都不匹配重定向 URL:Since no rules in the sample app match on the redirect URL:

  • 第二个请求从应用程序收到“200 (正常)”响应。The second request receives a 200 - OK response from the app.
  • 响应正文显示了重定向 URL。The body of the response shows the redirect URL.

重定向 URL 时,系统将向服务器进行一次往返。A round trip is made to the server when a URL is redirected.

警告

建立重定向规则时务必小心。Be cautious when establishing redirect rules. 系统会根据应用的每个请求(包括重定向后的请求)对重定向规则进行评估。Redirect rules are evaluated on every request to the app, including after a redirect. 很容易便会意外创建无限重定向循环。It's easy to accidentally create a loop of infinite redirects.

原始请求:/redirect-rule/1234/5678Original Request: /redirect-rule/1234/5678

开发人员工具正跟踪请求和响应的浏览器窗口

括号内的表达式部分称为“捕获组”。The part of the expression contained within parentheses is called a capture group. 表达式的点 (.) 表示匹配任何字符。The dot (.) of the expression means match any character. 星号 (*) 表示零次或多次匹配前面的字符。The asterisk (*) indicates match the preceding character zero or more times. 因此,URL 的最后两个路径段 1234/5678 由捕获组 (.*) 捕获。Therefore, the last two path segments of the URL, 1234/5678, are captured by capture group (.*). 在请求 URL 中提供的位于 redirect-rule/ 之后的任何值均由此单个捕获组捕获。Any value you provide in the request URL after redirect-rule/ is captured by this single capture group.

在替换字符串中,将捕获组注入带有美元符号 ($)、后跟捕获序列号的字符串中。In the replacement string, captured groups are injected into the string with the dollar sign ($) followed by the sequence number of the capture. 获取的第一个捕获组值为 $1,第二个为 $2,并且正则表达式中的其他捕获组值将依次继续排列。The first capture group value is obtained with $1, the second with $2, and they continue in sequence for the capture groups in your regex. 示例应用的重定向规则正则表达式中只有一个捕获组,因此替换字符串中只有一个注入组,即 $1There's only one captured group in the redirect rule regex in the sample app, so there's only one injected group in the replacement string, which is $1. 如果应用此规则,URL 将变为 /redirected/1234/5678When the rule is applied, the URL becomes /redirected/1234/5678.

URL 重定向到安全的终结点URL redirect to a secure endpoint

使用 AddRedirectToHttps 将 HTTP 请求重定向到采用 HTTPS 协议的相同主机和路径。Use AddRedirectToHttps to redirect HTTP requests to the same host and path using the HTTPS protocol. 如不提供状态代码,则中间件默认为“302(已找到)”。If the status code isn't supplied, the middleware defaults to 302 - Found. 如果不提供端口:If the port isn't supplied:

  • 中间件默认为 nullThe middleware defaults to null.
  • 方案更改为 https(HTTPS 协议),客户端访问端口 443 上的资源。The scheme changes to https (HTTPS protocol), and the client accesses the resource on port 443.

下面的示例演示如何将状态代码设置为“301(永久移动)”并将端口更改为 5001。The following example shows how to set the status code to 301 - Moved Permanently and change the port to 5001.

public void Configure(IApplicationBuilder app)
{
    var options = new RewriteOptions()
        .AddRedirectToHttps(301, 5001);

    app.UseRewriter(options);
}

使用 AddRedirectToHttpsPermanent 将不安全的请求重定向到端口 443 上的采用安全 HTTPS 协议的相同主机和路径。Use AddRedirectToHttpsPermanent to redirect insecure requests to the same host and path with secure HTTPS protocol on port 443. 中间件将状态代码设置为“301 (永久移动)”。The middleware sets the status code to 301 - Moved Permanently.

public void Configure(IApplicationBuilder app)
{
    var options = new RewriteOptions()
        .AddRedirectToHttpsPermanent();

    app.UseRewriter(options);
}

备注

当重定向到安全的终结点并且不需要其他重定向规则时,建议使用 HTTPS 重定向中间件。When redirecting to a secure endpoint without the requirement for additional redirect rules, we recommend using HTTPS Redirection Middleware. 有关详细信息,请参阅强制使用 HTTPS主题。For more information, see the Enforce HTTPS topic.

示例应用能够演示如何使用 AddRedirectToHttpsAddRedirectToHttpsPermanentThe sample app is capable of demonstrating how to use AddRedirectToHttps or AddRedirectToHttpsPermanent. 将扩展方法添加到 RewriteOptionsAdd the extension method to the RewriteOptions. 在任何 URL 上向应用发出不安全的请求。Make an insecure request to the app at any URL. 消除自签名证书不受信任的浏览器安全警告,或创建例外以信任证书。Dismiss the browser security warning that the self-signed certificate is untrusted or create an exception to trust the certificate.

使用 AddRedirectToHttps(301, 5001) 的原始请求:http://localhost:5000/secureOriginal Request using AddRedirectToHttps(301, 5001): http://localhost:5000/secure

开发人员工具正跟踪请求和响应的浏览器窗口

使用 AddRedirectToHttpsPermanent 的原始请求:http://localhost:5000/secureOriginal Request using AddRedirectToHttpsPermanent: http://localhost:5000/secure

开发人员工具正跟踪请求和响应的浏览器窗口

URL 重写URL rewrite

使用 AddRewrite 创建重写 URL 的规则。Use AddRewrite to create a rule for rewriting URLs. 第一个参数包含用于匹配传入 URL 路径的正则表达式。The first parameter contains the regex for matching on the incoming URL path. 第二个参数是替换字符串。The second parameter is the replacement string. 第三个参数 skipRemainingRules: {true|false} 指示如果当前规则适用,中间件是否要跳过其他重写规则。The third parameter, skipRemainingRules: {true|false}, indicates to the middleware whether or not to skip additional rewrite rules if the current rule is applied.

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

原始请求:/rewrite-rule/1234/5678Original Request: /rewrite-rule/1234/5678

开发人员工具正跟踪请求和响应的浏览器窗口

表达式开头的脱字号 (^) 意味着匹配从 URL 路径的开头处开始。The carat (^) at the beginning of the expression means that matching starts at the beginning of the URL path.

在前面的重定向规则 redirect-rule/(.*) 的示例中,正则表达式的开头没有脱字号 (^)。In the earlier example with the redirect rule, redirect-rule/(.*), there's no carat (^) at the start of the regex. 因此,路径中 redirect-rule/ 之前的任何字符都可能成功匹配。Therefore, any characters may precede redirect-rule/ in the path for a successful match.

路径Path 匹配Match
/redirect-rule/1234/5678 Yes
/my-cool-redirect-rule/1234/5678 Yes
/anotherredirect-rule/1234/5678 Yes

重写规则 ^rewrite-rule/(\d+)/(\d+) 只能与以 rewrite-rule/ 开头的路径匹配。The rewrite rule, ^rewrite-rule/(\d+)/(\d+), only matches paths if they start with rewrite-rule/. 注意下表中的匹配差异。In the following table, note the difference in matching.

路径Path 匹配Match
/rewrite-rule/1234/5678 Yes
/my-cool-rewrite-rule/1234/5678 No
/anotherrewrite-rule/1234/5678 No

在表达式的 ^rewrite-rule/ 部分之后,有两个捕获组 (\d+)/(\d+)Following the ^rewrite-rule/ portion of the expression, there are two capture groups, (\d+)/(\d+). \d 表示与数字匹配。The \d signifies match a digit (number). 加号 (+) 表示与前面的一个或多个字符匹配。The plus sign (+) means match one or more of the preceding character. 因此,URL 必须包含数字加正斜杠加另一个数字的形式。Therefore, the URL must contain a number followed by a forward-slash followed by another number. 这些捕获组以 $1$2 的形式注入重写 URL 中。These capture groups are injected into the rewritten URL as $1 and $2. 重写规则替换字符串将捕获组放入查询字符串中。The rewrite rule replacement string places the captured groups into the query string. 重写 /rewrite-rule/1234/5678 的请求路径,获取 /rewritten?var1=1234&var2=5678 处的资源。The requested path of /rewrite-rule/1234/5678 is rewritten to obtain the resource at /rewritten?var1=1234&var2=5678. 如果原始请求中存在查询字符串,则重写 URL 时会保留此字符串。If a query string is present on the original request, it's preserved when the URL is rewritten.

无需往返服务器来获取资源。There's no round trip to the server to obtain the resource. 如果资源存在,系统会提取资源并以“200(正常)”状态代码返回给客户端。If the resource exists, it's fetched and returned to the client with a 200 - OK status code. 因为客户端不会被重定向,所以浏览器地址栏中的 URL 不会发生更改。Because the client isn't redirected, the URL in the browser's address bar doesn't change. 客户端无法检测到服务器上发生的 URL 重写操作。Clients can't detect that a URL rewrite operation occurred on the server.

备注

尽可能使用 skipRemainingRules: true,因为匹配规则在计算上很昂贵并且增加了应用响应时间。Use skipRemainingRules: true whenever possible because matching rules is computationally expensive and increases app response time. 对于最快的应用响应:For the fastest app response:

  • 按照从最频繁匹配的规则到最不频繁匹配的规则排列重写规则。Order rewrite rules from the most frequently matched rule to the least frequently matched rule.
  • 如果出现匹配项且无需处理任何其他规则,则跳过剩余规则的处理。Skip the processing of the remaining rules when a match occurs and no additional rule processing is required.

Apache mod_rewriteApache mod_rewrite

使用 AddApacheModRewrite 应用 Apache mod_rewrite 规则。Apply Apache mod_rewrite rules with AddApacheModRewrite. 请确保将规则文件与应用一起部署。Make sure that the rules file is deployed with the app. 有关 mod_rewrite 规则的详细信息和示例,请参阅 Apache mod_rewriteFor more information and examples of mod_rewrite rules, see Apache mod_rewrite.

StreamReader 用于读取 ApacheModRewrite.txt 规则文件中的规则:A StreamReader is used to read the rules from the ApacheModRewrite.txt rules file:

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

示例应用将请求从 /apache-mod-rules-redirect/(.\*) 重定向到 /redirected?id=$1The sample app redirects requests from /apache-mod-rules-redirect/(.\*) to /redirected?id=$1. 响应状态代码为“302 (已找到)”。The response status code is 302 - Found.

# Rewrite path with additional sub directory
RewriteRule ^/apache-mod-rules-redirect/(.*) /redirected?id=$1 [L,R=302]

原始请求:/apache-mod-rules-redirect/1234Original Request: /apache-mod-rules-redirect/1234

开发人员工具正跟踪请求和响应的浏览器窗口

中间件支持下列 Apache mod_rewrite 服务器变量:The middleware supports the following Apache mod_rewrite server variables:

  • CONN_REMOTE_ADDRCONN_REMOTE_ADDR
  • HTTP_ACCEPTHTTP_ACCEPT
  • HTTP_CONNECTIONHTTP_CONNECTION
  • HTTP_COOKIEHTTP_COOKIE
  • HTTP_FORWARDEDHTTP_FORWARDED
  • HTTP_HOSTHTTP_HOST
  • HTTP_REFERERHTTP_REFERER
  • HTTP_USER_AGENTHTTP_USER_AGENT
  • HTTPSHTTPS
  • IPV6IPV6
  • QUERY_STRINGQUERY_STRING
  • REMOTE_ADDRREMOTE_ADDR
  • REMOTE_PORTREMOTE_PORT
  • REQUEST_FILENAMEREQUEST_FILENAME
  • REQUEST_METHODREQUEST_METHOD
  • REQUEST_SCHEMEREQUEST_SCHEME
  • REQUEST_URIREQUEST_URI
  • SCRIPT_FILENAMESCRIPT_FILENAME
  • SERVER_ADDRSERVER_ADDR
  • SERVER_PORTSERVER_PORT
  • SERVER_PROTOCOLSERVER_PROTOCOL
  • TIMETIME
  • TIME_DAYTIME_DAY
  • TIME_HOURTIME_HOUR
  • TIME_MINTIME_MIN
  • TIME_MONTIME_MON
  • TIME_SECTIME_SEC
  • TIME_WDAYTIME_WDAY
  • TIME_YEARTIME_YEAR

IIS URL 重写模块规则IIS URL Rewrite Module rules

若要使用适用于 IIS URL 重写模块的同一规则集,使用 AddIISUrlRewriteTo use the same rule set that applies to the IIS URL Rewrite Module, use AddIISUrlRewrite. 请确保将规则文件与应用一起部署。Make sure that the rules file is deployed with the app. 当在 Windows Server IIS 上运行时,请勿指示中间件使用应用的 web.config 文件。Don't direct the middleware to use the app's web.config file when running on Windows Server IIS. 使用 IIS 时,应将这些规则存储在应用的 web.config 文件之外,以避免与 IIS 重写模块发生冲突。With IIS, these rules should be stored outside of the app's web.config file in order to avoid conflicts with the IIS Rewrite module. 有关 IIS URL 重写模块规则的详细信息和示例,请参阅 Using Url Rewrite Module 2.0(使用 URL 重写模块 2.0)和 URL Rewrite Module Configuration Reference(URL 重写模块配置引用)。For more information and examples of IIS URL Rewrite Module rules, see Using Url Rewrite Module 2.0 and URL Rewrite Module Configuration Reference.

StreamReader 用于读取 IISUrlRewrite.xml 规则文件中的规则:A StreamReader is used to read the rules from the IISUrlRewrite.xml rules file:

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

示例应用将请求从 /iis-rules-rewrite/(.*) 重写为 /rewritten?id=$1The sample app rewrites requests from /iis-rules-rewrite/(.*) to /rewritten?id=$1. 以“200 (正常)”状态代码作为响应发送到客户端。The response is sent to the client with a 200 - OK status code.

<rewrite>
  <rules>
    <rule name="Rewrite segment to id querystring" stopProcessing="true">
      <match url="^iis-rules-rewrite/(.*)$" />
      <action type="Rewrite" url="rewritten?id={R:1}" appendQueryString="false"/>
    </rule>
  </rules>
</rewrite>

原始请求:/iis-rules-rewrite/1234Original Request: /iis-rules-rewrite/1234

开发人员工具正跟踪请求和响应的浏览器窗口

如果有配置了服务器级别规则(可对应用产生不利影响)的活动 IIS 重写模块,则可禁用应用的 IIS 重写模块。If you have an active IIS Rewrite Module with server-level rules configured that would impact your app in undesirable ways, you can disable the IIS Rewrite Module for an app. 有关详细信息,请参阅禁用 IIS 模块For more information, see Disabling IIS modules.

不支持的功能Unsupported features

与 ASP.NET Core 2.x 一同发布的中间件不支持以下 IIS URL 重写模块功能:The middleware released with ASP.NET Core 2.x doesn't support the following IIS URL Rewrite Module features:

  • 出站规则Outbound Rules
  • 自定义服务器变量Custom Server Variables
  • 通配符Wildcards
  • LogRewrittenUrlLogRewrittenUrl

受支持的服务器变量Supported server variables

中间件支持下列 IIS URL 重写模块服务器变量:The middleware supports the following IIS URL Rewrite Module server variables:

  • CONTENT_LENGTHCONTENT_LENGTH
  • CONTENT_TYPECONTENT_TYPE
  • HTTP_ACCEPTHTTP_ACCEPT
  • HTTP_CONNECTIONHTTP_CONNECTION
  • HTTP_COOKIEHTTP_COOKIE
  • HTTP_HOSTHTTP_HOST
  • HTTP_REFERERHTTP_REFERER
  • HTTP_URLHTTP_URL
  • HTTP_USER_AGENTHTTP_USER_AGENT
  • HTTPSHTTPS
  • LOCAL_ADDRLOCAL_ADDR
  • QUERY_STRINGQUERY_STRING
  • REMOTE_ADDRREMOTE_ADDR
  • REMOTE_PORTREMOTE_PORT
  • REQUEST_FILENAMEREQUEST_FILENAME
  • REQUEST_URIREQUEST_URI

备注

也可通过 PhysicalFileProvider 获取 IFileProviderYou can also obtain an IFileProvider via a PhysicalFileProvider. 这种方法可为重写规则文件的位置提供更大的灵活性。This approach may provide greater flexibility for the location of your rewrite rules files. 请确保将重写规则文件部署到所提供路径的服务器中。Make sure that your rewrite rules files are deployed to the server at the path you provide.

PhysicalFileProvider fileProvider = new PhysicalFileProvider(Directory.GetCurrentDirectory());

基于方法的规则Method-based rule

使用 Add 在方法中实现自己的规则逻辑。Use Add to implement your own rule logic in a method. Add 公开 RewriteContext,这使 HttpContext 可用于方法中。Add exposes the RewriteContext, which makes available the HttpContext for use in your method. RewriteContext.Result 决定如何处理其他管道进程。The RewriteContext.Result determines how additional pipeline processing is handled. 将值设置为下表中的 RuleResult 字段之一。Set the value to one of the RuleResult fields described in the following table.

重写上下文结果Rewrite context result 操作Action
RuleResult.ContinueRules(默认值)RuleResult.ContinueRules (default) 继续应用规则。Continue applying rules.
RuleResult.EndResponse 停止应用规则并发送响应。Stop applying rules and send the response.
RuleResult.SkipRemainingRules 停止应用规则并将上下文发送给下一个中间件。Stop applying rules and send the context to the next middleware.
public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

示例应用演示了如何对以 .xml 结尾的路径的请求进行重定向。The sample app demonstrates a method that redirects requests for paths that end with .xml. 如果发出针对 /file.xml 的请求,请求将重定向到 /xmlfiles/file.xmlIf a request is made for /file.xml, the request is redirected to /xmlfiles/file.xml. 状态代码设置为“301 (永久移动)”。The status code is set to 301 - Moved Permanently. 当浏览器发出针对 /xmlfiles/file.xml 的新请求后,静态文件中间件会将文件从 wwwroot / xmlfiles 文件夹提供给客户端 。When the browser makes a new request for /xmlfiles/file.xml, Static File Middleware serves the file to the client from the wwwroot/xmlfiles folder. 对于重定向,请显式设置响应的状态代码。For a redirect, explicitly set the status code of the response. 否则,将会返回“200 (正常)”状态代码,且客户端上不会发生重写。Otherwise, a 200 - OK status code is returned, and the redirect doesn't occur on the client.

RewriteRules.cs:RewriteRules.cs:

public static void RedirectXmlFileRequests(RewriteContext context)
{
    var request = context.HttpContext.Request;

    // Because the client is redirecting back to the same app, stop 
    // processing if the request has already been redirected.
    if (request.Path.StartsWithSegments(new PathString("/xmlfiles")))
    {
        return;
    }

    if (request.Path.Value.EndsWith(".xml", StringComparison.OrdinalIgnoreCase))
    {
        var response = context.HttpContext.Response;
        response.StatusCode = StatusCodes.Status301MovedPermanently;
        context.Result = RuleResult.EndResponse;
        response.Headers[HeaderNames.Location] = 
            "/xmlfiles" + request.Path + request.QueryString;
    }
}

此方法还可以重写请求。This approach can also rewrite requests. 示例应用演示了如何重写任何文本文件请求的路径以从 wwwroot 文件夹中提供 file.txt 文本文件 。The sample app demonstrates rewriting the path for any text file request to serve the file.txt text file from the wwwroot folder. 静态文件中间件基于更新的请求路径来提供文件:Static File Middleware serves the file based on the updated request path:

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

RewriteRules.cs:RewriteRules.cs:

public static void RewriteTextFileRequests(RewriteContext context)
{
    var request = context.HttpContext.Request;

    if (request.Path.Value.EndsWith(".txt", StringComparison.OrdinalIgnoreCase))
    {
        context.Result = RuleResult.SkipRemainingRules;
        request.Path = "/file.txt";
    }
}

基于 IRule 的规则IRule-based rule

使用 Add 在实现 IRule 接口的类中使用规则逻辑。Use Add to use rule logic in a class that implements the IRule interface. 与使用基于方法的规则方法相比,IRule 提供了更大的灵活性。IRule provides greater flexibility over using the method-based rule approach. 实现类可能包含构造函数,可在其中传入 ApplyRule 方法的参数。Your implementation class may include a constructor that allows you can pass in parameters for the ApplyRule method.

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

检查示例应用中 extensionnewPath 的参数值是否符合多个条件。The values of the parameters in the sample app for the extension and the newPath are checked to meet several conditions. extension 须包含一个值,并且该值必须是 .png、.jpg 或 .gif 。The extension must contain a value, and the value must be .png, .jpg, or .gif. 如果 newPath 无效,则会引发 ArgumentExceptionIf the newPath isn't valid, an ArgumentException is thrown. 如果发出针对 image.png 的请求,请求将重定向到 /png-images/image.pngIf a request is made for image.png, the request is redirected to /png-images/image.png. 如果发出针对 image.png 的请求,请求将重定向到 /jpg-images/image.jpgIf a request is made for image.jpg, the request is redirected to /jpg-images/image.jpg. 状态代码设置为“301 (永久移动)”,context.Result 设置为停止处理规则并发送响应。The status code is set to 301 - Moved Permanently, and the context.Result is set to stop processing rules and send the response.

public class RedirectImageRequests : IRule
{
    private readonly string _extension;
    private readonly PathString _newPath;

    public RedirectImageRequests(string extension, string newPath)
    {
        if (string.IsNullOrEmpty(extension))
        {
            throw new ArgumentException(nameof(extension));
        }

        if (!Regex.IsMatch(extension, @"^\.(png|jpg|gif)$"))
        {
            throw new ArgumentException("Invalid extension", nameof(extension));
        }

        if (!Regex.IsMatch(newPath, @"(/[A-Za-z0-9]+)+?"))
        {
            throw new ArgumentException("Invalid path", nameof(newPath));
        }

        _extension = extension;
        _newPath = new PathString(newPath);
    }

    public void ApplyRule(RewriteContext context)
    {
        var request = context.HttpContext.Request;

        // Because we're redirecting back to the same app, stop 
        // processing if the request has already been redirected
        if (request.Path.StartsWithSegments(new PathString(_newPath)))
        {
            return;
        }

        if (request.Path.Value.EndsWith(_extension, StringComparison.OrdinalIgnoreCase))
        {
            var response = context.HttpContext.Response;
            response.StatusCode = StatusCodes.Status301MovedPermanently;
            context.Result = RuleResult.EndResponse;
            response.Headers[HeaderNames.Location] = 
                _newPath + request.Path + request.QueryString;
        }
    }
}

原始请求:/image.pngOriginal Request: /image.png

开发人员工具正跟踪 image.png 的请求和响应的浏览器窗口

原始请求:/image.jpgOriginal Request: /image.jpg

开发人员工具正跟踪 image.jpg 的请求和响应的浏览器窗口

正则表达式示例Regex examples

目标Goal 正则表达式字符串和Regex String &
匹配示例Match Example
替换字符串和Replacement String &
输出示例Output Example
将路径重写为查询字符串Rewrite path into querystring ^path/(.*)/(.*)
/path/abc/123
path?var1=$1&var2=$2
/path?var1=abc&var2=123
去掉尾部反斜杠Strip trailing slash (.*)/$
/path/
$1
/path
强制添加尾部反斜杠Enforce trailing slash (.*[^/])$
/path
$1/
/path/
避免重写特定请求Avoid rewriting specific requests ^(.*)(?<!\.axd)$^(?!.*\.axd$)(.*)$^(.*)(?<!\.axd)$ or ^(?!.*\.axd$)(.*)$
正确:/resource.htmYes: /resource.htm
错误:/resource.axdNo: /resource.axd
rewritten/$1
/rewritten/resource.htm
/resource.axd
重新排列 URL 段Rearrange URL segments path/(.*)/(.*)/(.*)
path/1/2/3
path/$3/$2/$1
path/3/2/1
替换 URL 段Replace a URL segment ^(.*)/segment2/(.*)
/segment1/segment2/segment3
$1/replaced/$2
/segment1/replaced/segment3

其他资源Additional resources