ASP.NET Web Forms 的 URL 重写

作者:Ruslan Yakushev

将 IIS URL 重写模块与 ASP.NET 应用程序结合使用时,请务必确保 Web 应用程序在使用重写 URL 时行为正确。 本文介绍了 URL 重写可能影响 ASP.NET Web 应用程序的情况,以及潜在问题的解决方案。

目录

设置窗体元素的回发 URL

ASP.NET Web Forms 广泛使用回发,这使得对 ASP.NET 页面执行 URL 重写有点棘手。 如果页面包含一个或多个 Web 服务器控件,ASP.NET 在渲染页面时会将 HTML 窗体元素的 action 属性设置为指向窗体元素所在的页面,即指向它自己。 如果该页面使用了 URL 重写,则 action 属性指向重写后的 URL,而不是从浏览器请求的 URL。 这样,浏览器在回发时就会在地址框中显示重写后的 URL。

为防止 action 属性指向错误的 URL,可以将页面上 HtmlForm 实例的 Action 属性设置为浏览器请求的回发 URL。 可以使用 HttpRequest.RawUrl 属性获取该 URL。 以下示例演示如何修改 ASP.NET 页面以设置操作 URL。

protected void Page_Load(object sender, EventArgs e) 
{ 
    form1.Action = Request.RawUrl; 
}

注意

从 .NET Framework 版本 3.5 SP1 开始,可以使用 HtmlForm.Action 属性。

如果使用 ASP.NET 母版页,可以在母版页的 Page_Load 方法中添加代码,为使用该母版页的所有页面设置回发操作 URL。

重写 AJAX UpdatePanel 控件的 URL

当你使用 URL 重写模块为包含一个或多个 UpdatePanel 控件的页面重写 URL 时,该控件会将重写后的 URL 用于该 UpdatePanel 控件执行的所有操作。 这可能导致 UpdatePanel 控件中的控件无法正常工作,尤其是在 URL 重写更改了所请求 URL 的目录层次结构的情况下。 例如,如果使用 URL 重写模块将 //Products/Hardware 重写为 /Products.aspx,UpdatePanel 控件将在 UpdatePanel 控件内的所有操作中使用 URL /Products/Hardware/Products.aspx。 这会导致脚本错误。

若要防止发生这种情况,请设置页面的 HtmlForm 实例的 Action 属性,如上一部分中设置窗体元素的回发 URL 中所述。

在 Web 服务器控件中使用 ~ 运算符

需要设置路径时,可以在 ASP.NET Web 服务器控件中使用 ~ 运算符来引用应用程序目录的根目录。 但是,如果 URL 重写改变了所请求 URL 的目录层次结构,这可能导致使用 ~ 运算符指定的链接被错误解析。 例如,假设名为 app1 的 Web 应用程序根目录下的 Default.aspx 页面包含以下图像控件:

<asp:Image runat="server" ImageUrl="~/Images/MyImage.gif" />

如果 URL 重写将 URL 从 http://localhost/app1/folder/file 更改为 http://localhost/app1/default.aspx,则使用 ~ 运算符指定的链接将相对于重写的 URL 路径(相对于 /app1 文件夹)解析。 以下示例显示 img 元素的生成的 HTML 标记:

<img src="Images/MyImage.gif" ... >

由于浏览器已请求 http://localhost/app1/folder/file,因此它将尝试从 http://localhost/app1/folder/Images/MyImage.gif 中获取图像。 这会导致 404(找不到文件)错误。

IIS 的 URL 重写模块包括修复此行为的 ASP.NET 的更新。 更新会导致 Web 服务器控件中的 ~ 运算符相对于最初请求的 URL 进行解析。 在上一个示例中,响应中的 HTML 标记将包含 img 元素的正确 URL 路径,如以下标记所示:

<img src="../Images/MyImage.gif" ... >

ASP.NET 的更新仅适用于 .NET Framework 3.5 SP1 及更高版本。 要获得更新,请将 .NET Framework 升级到 3.5 SP1 版本,然后运行 IIS URL 重写模块安装程序,该程序将安装 ASP.NET 更新。

重写 URL 和站点导航控件

ASP.NET 站点地图可用于描述网站的结构,使站点导航 API 和站点导航控件可以公开站点的逻辑结构(而不是物理结构)。 将 URL 重写模块与使用站点导航的 ASP.NET 应用程序结合使用时,通常需要导航控件在使用公共或虚拟 URL 的逻辑站点结构中运行。

例如,可以定义站点地图,如以下示例所示:

<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0">
  <siteMapNode url="~/Products/" title="Products" description="Products Home Page">   
    <siteMapNode url="~/Products/Hardware/" title="Hardware" description="Hardware Products" /> 
    <siteMapNode url="~/Products/Software/" title="Software" description="Software Products" />
  </siteMapNode>
</siteMap>

然后,可以定义执行以下重写的重写规则:

  • /Products/ 重写为 /Products.aspx
  • /Products/Hardware 重写为 /Products.aspx?category=Hardware
  • /Products/Software 重写为 /Products.aspx?category=Software

使用这些虚拟 URL 定义站点地图可能导致 SystemWeb.SiteMap 类无法正常工作。 尝试访问 ASP.NET 页面中的 SiteMap.CurrentNode 属性时,该属性可能包含 null。 这可能会导致站点导航控件(如 SiteMapPath 和 Menu)无法正常工作。

IIS 的 URL 重写模块包括针对 ASP.NET 的更新,可修复导航控件,使其可与重写后的虚拟 URL 配合使用。 更新后,SiteMap.CurrentNode 属性将引用与当前请求的虚拟 URL 相对应的 SiteMapNode。

ASP.NET 的更新仅适用于 .NET Framework 3.5 SP1 及更高版本。 要获得更新,请将 .NET Framework 升级到 3.5 SP1 版本,然后运行 IIS URL 重写模块安装程序,该程序将安装 ASP.NET 更新。

阻止重写 ASP.NET Web 资源的请求

基于 ASP.NET 的 Web 应用程序经常向 WebResources.axd 文件发出请求,以检索程序集资源并将其提供给 Web 浏览器。 服务器上不存在此类文件,因为在请求 WebResources.axd 时,ASP.NET 动态生成内容。 因此,如果 URL 重写规则仅在请求的 URL 与 Web 服务器文件系统中的文件或文件夹不对应时才进行重写或重定向,那么该规则可能会意外重写向 WebResources.axd 发出的请求,从而破坏应用程序。

如果在重写规则中添加一个额外的条件,可以轻松避免这个问题:

<rule name="RewriteUserFriendlyURL1" stopProcessing="true">
  <match url="^([^/]+)/?$" />
  <conditions>
    <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
    <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
    <!--  The following condition prevents rule from rewriting requests to .axd files -->
    <add input="{URL}" negate="true" pattern="\.axd$" />
  </conditions>
  <action type="Rewrite" url="article.aspx?p={R:1}" />
</rule>