54

ASP.NET Core URL Rewrite中间件

 5 years ago
source link: http://www.10tiao.com/html/391/201807/2654071114/2.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

  URL重写是基于一个或多个预置规则修改请求URL的行为。URL重写在资源位置和访问地址之间创建了一种抽象,这样二者之间就减少了紧密的联系。URL重写有多种适用的场景:

  • 临时或永久移动或替换服务器资源,同时为这些资源保持稳定的访问

  • 为不同应用程序或同一个应用程序的不同区域的拆分请求处理

  • 根据请求移除、添加、重新组织URL段(segment)

  • SEO优化

  • 允许使用友好的公共URL来帮助人们通过链接预测找到内容

  • 将不安全的请求重定向到安全端点

  • 图片防盗链

  可以通过多种方式定义改变URL的规则,包括正则表达式、Apache mod_rewrite模块规则、IIS重写模块规则和自定义规则逻辑。本文介绍URL重写及说明如何在ASP.NET Core应用中使用URL重写中间件。

注意:URL重写可能会降低应用的性能,您应该尽可能的限制规则的数量和规则的复杂性。

 URL重定向和URL重写

  从字面意思上看URL重定向和URL重写的差异并不明显,但二者在提供资源给客户端方面都有重要意义。ASP.NET Core的URL重写中间件能够同时满足二者的需求。URL重定向是客户端操作,指示客户端在另一个地址访问资源,需要额外往返服务器。当客户端对资源发出请求时,返回到客户端的重定向URL将显示在浏览器的地址栏中。例如/resource被重定向到/different-resource时:客户端请求/resource,服务端响应客户端应在/different-resource获取资源,其响应的状态码会指示重定向是临时的还是永久的,然后客户端会向/different-resource发送一个新请求获取资源。

  将请求重定向到其他URL时,可以指定重定向是永久还是临时。301(Moved Permanently)状态代码用于表明资源具有新的永久URL,并且希望客户端将来对该资源的所有请求都应使用新URL。当收到301状态码时客户端可以缓存响应。302(Found)状态码用于临时重定向,所以客户端不应该存储和重用该URL。状态码的含义请参考这里。URL重写是服务器端操作,用于从不同的资源地址提供资源。URL重写不需要额外的往返服务器,并且重写后的URL不会返回给客户端,也不会出现在客户端的地址栏中。当/resource被重写为/different-resource时:客户端请求/resource,服务端在内部从/different-resource获取资源并响应给客户端。尽管客户端也许可以从重写后的URL处获取资源,但客户端并不会收到资源存在于重写后URL的通知。

何时使用URL重写中间件

  当无法在Windows Server上使用IIS重写模块、Apache服务器上的Apache mod_rewrite模块、Nginx上的URL重写或应用程序托管在HTTP.sys服务器(以前称为WebListener)上时,请使用URL重写中间件。推荐在IIS,Apache或Nginx中使用基于服务器的URL重写技术的主要原因是中间件不支持这些模块的全部功能,并且中间件的性能可能无法达到这些模块的性能。但是,这些服务器重写模块的某些功能不适用于ASP.NET Core项目,例如IIS Rewrite模块的IsFile和IsDirectory。在这些情况下,请改用中间件。

包引用

  要在项目中使用URL重写中间件,请添加Microsoft.AspNetCore.Rewrite包的引用。该功能适用于ASP.NET Core 1.1或更高版本的应用程序。

配置重写及重定向规则

  通过RewriteOptions类实例的扩展方法来建立URL重写和重定向规则,按照你希望处理的顺序将这些规则链接起来,然后通过使用app.UseRewriter(options)将URL重写选项传递到请求管道,以下是几种重写、重定向的配置代码,后面会针对每种配置单独解释:

URL重定向

  使用AddRedirect方法重定向请求,第一个参数为匹配请求URL的正则表达式,第二个参数为替换的文本,第三个参数(如果存在)指定状态码,如果未指定状态码,默认为302(Found)。

  打开浏览器的开发者工具,向/redirect-rule/1234/5678发送一个请求。重定向规则中的正则表达式将匹配请求路径,将路径替换为/redirected/1234/5678,服务端将重定向URL和302(Found)状态代码发送回客户端。客户端基于该URL发送新请求并将该URL显示到地址栏中,然后客户端收到一个200(OK)的响应。

警告:新建重定向规则时一定要谨慎,重定向规则将会对应用每一个请求都进行匹配,包括重定向后的URL。所以很容易不小心创建一个无限重定向循环。

   发送一个请求:/redirect-rule/1234/5678,响应如下图:

 

  重定向规则中正则表达式括号内的部分称为捕获组,表达式中点(.)的含义是匹配任何字符,星号(*)表示匹配之前的字符零次或者多次。因此,URL中最后两段/123/5678被(.*)捕获组所捕获,URL中位于redirect-rule/之后的任何值都将会被该组捕获。
在替换字符串中,捕获组将捕获的内容注入到($n)符号所在位置,其中$后的数字n代表捕获的序列号。第一个捕获组是$1,第二个是$2,以此类推。在上面的例子中,重定向规则中的正则表达式只有一个捕获组,所以替换字符串中只有一个$1,最终/redirect-rule/1234/5678被替换为/redirect-rule/1234/5678。

URL重定向到安全站点

  可使用AddRedirectToHttps方法将不安全的请求重定向到具有安全HTTPS协议的同一主机和路径,如果未提供状态码参数,中间件将使用默认值302(Found)。如果未提供端口号参数,中间件使用默认值null,这意味着客户端将使用https协议同时从443端口访问资源,下面的代码片段演示如何将重定向状态码设为301(Moved Permanently),同时将端口设为5001:

   也可以使用AddRedirectToHttpsPermanent方法将不安全的请求重定向到具有安全HTTPS协议的同一主机和路径(端口443上的https://)。中间件将响应状态码设置为301(Moved Permanently)。

注意:在不需要其他重定向规则的情况下重定向到HTTPS时,建议使用HTTPS重定向中间件。请参考这里

 URL重写

  可使用AddRewrite方法创建重写规则,第一个参数为匹配请求URL的正则表达式,第二个参数是替换字符串,第三个参数skipRemainingRules: {true|false},表示如果当前规则生效是否要跳过其它的重写规则。 

  发送一个请求:/rewrite-rule/1234/5678,重定向请求及响应如下图:

 

   我们注意到正则表达式开头是字符^,它的含义是匹配需要从URL路径的开头开始。在之前重定向例子中,正则表达式的开头并没有字符^,因此,路径中redirect-rule/之前的任何字符都可以成功匹配。

路径 是否匹配 /redirect-rule/1234/5678 是 /my-cool-redirect-rule/1234/5678 是  /anotherredirect-rule/1234/5678 是

  在重写规则中,正则表达式^rewrite-rule/(\d+)/(\d+)仅匹配以rewrite-rule/开头的路径,请注意二者之间的区别:

路径 是否匹配 /rewrite-rule/1234/5678 是 /my-cool-rewrite-rule/1234/5678 否 /anotherrewrite-rule/1234/5678 否

   在正则表达式^rewrite-rule/(\d+)/(\d+)中有两个捕获组:(\d+)/(\d+),\d表示匹配一个数字,加号(+)表示匹配之前的字符1次或者多次。因此,匹配的URL必须包含一个数字,后跟一个正斜杠,后跟另一个数字。捕获的内容将会被分别注入到重写字符串中的$1和$2位置。所以请求URL/rewrite-rule/1234/5678将会被重写为/rewritten?var1=1234&var2=5678。如果原始请求中存在查询字符串,则在重写URL时会保留该查询字符串。URL重写不会有额外的服务器往返。如果资源存在,服务端获取资源内容并返回给客户端200(OK)状态码。因为客户端没有被重定向,所以浏览器地址栏中的地址不会改变。就客户端而言,是感知不到URL重写的。

 注意:尽可能使用skipRemainingRules:true参数,因为匹配规则是一个昂贵的过程并增加了应用程序响应时间。为了更快的响应,请考虑以下建议:

  • 将重写规则排序:从最常匹配的规则到最不常匹配的规则

  • 规则匹配成功之后跳过剩余的规则

 使用Apache mod_rewrite规则

   使用AddApacheModRewrite方法应用Apache mod_rewrite规则,请确保规则文件已随应用程序部署至服务器。了解更多关于Apache mod_rewrite规则,请参考这里

以下为ApacheModRewrite.txt的内容:

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

示例应用程序将来自/apache-mod-rules-redirect/(.\*)的请求重定向到/redirected?id=$1,响应码为302(Found)。

中间件支持以下Apache mod_rewrite服务器变量:

  • CONN_REMOTE_ADDR

  • HTTP_ACCEPT

  • HTTP_CONNECTION

  • HTTP_COOKIE

  • HTTP_FORWARDED

  • HTTP_HOST

  • HTTP_REFERER

  • HTTP_USER_AGENT

  • HTTPS

  • IPV6

  • QUERY_STRING

  • REMOTE_ADDR

  • REMOTE_PORT

  • REQUEST_FILENAME

  • REQUEST_METHOD

  • REQUEST_SCHEME

  • REQUEST_URI

  • SCRIPT_FILENAME

  • SERVER_ADDR

  • SERVER_PORT

  • SERVER_PROTOCOL

  • TIME

  • TIME_DAY

  • TIME_HOUR

  • TIME_MIN

  • TIME_MON

  • TIME_SEC

  • TIME_WDAY

  • TIME_YEAR

使用IIS URL重写模块规则

  使用AddIISUrlRewrite方法应用IIS URL重写规则,请确保规则文件已随应用程序部署至服务器。在Windows Server IIS上运行时,不要让中间件直接使用web.config文件,规格文件应该存储于web.config之外,以避免和IIS重写模块冲突。了解更多关于IIS重写模块的规则,请参考这里和这里。

以下为IISUrlRewrite.xml的内容:

示例应用程序将来自/iis-rules-rewrite/(.*)的请求重写为/rewritten?id=$1,响应码为200(OK)。

ASP.NET Core 2.x发布的中间件不支持以下IIS URL重写模块功能:

  • Outbound Rules

  • Custom Server Variables

  • Wildcards

  • LogRewrittenUrl

中间件支持以下IIS URL重写模块服务器变量:

  • CONTENT_LENGTH

  • CONTENT_TYPE

  • HTTP_ACCEPT

  • HTTP_CONNECTION

  • HTTP_COOKIE

  • HTTP_HOST

  • HTTP_REFERER

  • HTTP_URL

  • HTTP_USER_AGENT

  • HTTPS

  • LOCAL_ADDR

  • QUERY_STRING

  • REMOTE_ADDR

  • REMOTE_PORT

  • REQUEST_FILENAME

  • REQUEST_URI

注意:可以通过PhysicalFileProvider类获取IFileProvider。这种方法可以为重写规则文件的位置提供更大的灵活性。

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

基于方法的规则

  使用Add(Action<RewriteContext> applyRule)在方法中实现自己的规则逻辑,RewriteContext公开HttpContext以方便在方法中使用,而context.Result决定了如何进行后续的管道处理。如下表:

context.Result 行为 RuleResult.ContinueRules(默认行为) 继续应用后续规则 RuleResult.EndResponse 停止应用规则并发送响应 RuleResult.SkipRemainingRules 停止应用规则并发送上下文(HttpContext)至下个中间件

  示例应用程序演示了将.xml结尾的请求路径重定向的自定义逻辑方法。如果对/file.xml发出请求,则会将其重定向到/xmlfiles/file.xml。响应码被设置为301 (Moved Permanently)。对于重定向来说,你必须显式指定响应的状态码,否则响应码将被默认为200(OK)且客户端也不会发生重定向。

   发送一个请求:/file.xml,响应如下图:

基于IRule接口的规则

  使用Add(IRule)在从IRule派生的类中实现您自己的规则逻辑。使用IRule的方式比使用基于方法的规则方法具有更好的灵活性,派生类可以包含构造函数,您可以在其中传递ApplyRule方法的参数。

 发送一个请求:/image.png,响应内容如下:

尾语

  本来主要内容来自于微软官方英文文档,点击这里查看原文,在翻译过程中,对有些句式和词汇进行了加工,以期望更加流畅和符合我们的阅读习惯,其中应该有不少不得体的地方,还请各位大神见谅并指出,如有一丝帮助,万分荣幸。

原文地址:https://www.cnblogs.com/luohelc/p/url_rewrite.html

.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK