【问题标题】:Configuring Web API with URL Rewrite installed on IIS使用安装在 IIS 上的 URL 重写配置 Web API
【发布时间】:2018-02-08 14:36:11
【问题描述】:

我们有一个使用 ASP.Net URL Rewrite 2.0 的 Web 窗体应用程序。以下重写规则配置为无需指定 .ashx 扩展即可访问某些页面:

<rule name="RewriteASHX">
    <match url="(customers|orders|products.*)"/>
    <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}.ashx"/>
</rule>

使用 Web API,我们希望逐渐将基于 Web 表单的 API 页面替换为 Web API 控制器。安装 URL Rewrite 后,只有符合上述规则的控制器才能正确路由到 Web API 控制器。 (向 URL 重写规则添加排除项似乎根本不允许请求到达控制器,从而给出 404 结果。)

Web API 控制器按以下方式设置:

public class CustomersController : ApiController
{
    [Route("api/v2/customers")]
    [ResponseType(typeof(CustomerCollection))]
    public IHttpActionResult Get()
    {
        ...
    }

    [Route("api/v2/customers/{identifier}")]
    [ResponseType(typeof(Customer))]
    public IHttpActionResult Get(string identifier)
    {
        ...
    }
}

如上所述,我们只有在 Web API 请求与 URL 重写条件匹配时才能获取路由。

CustomerController 中的无参数api/v2/customers 有效,因为它匹配&lt;match url="(customers|orders|products.*)"/&gt;,但api/v2/customers/C123 失败,因为它不匹配重写条件。

配置 URL 重写以允许 Web API 请求正确路由的最佳方法是什么?

【问题讨论】:

    标签: c# asp.net url-rewriting webforms asp.net-web-api2


    【解决方案1】:

    URL 重写模块基本上有 2 个不同的功能:

    1. 重写传入的 URL 以使其“看起来”像 Web 服务器的另一个 URL
    2. 将传入 URL 重定向到另一个 URL

    自从引入了 .NET 路由(用于 ASP.NET、ASP.NET MVC 和 Web API),URL 重写在很大程度上是不必要的。路由要好得多。通过路由,传入的请求完全发送到目标控制器方法。通过重写,HTTP 上下文被重写以欺骗 ASP.NET 将请求发送到其他地方,这可能会导致依赖 HTTP 上下文值工作的事物出现问题。

    另一方面,重定向对于 URL 重写仍然非常有用。特别是当涉及到您正在升级的旧应用程序的旧 URL 时。为了确保所有旧 URL 都能正常工作(并且不损害搜索引擎排名),请使用 301 重定向。 301 重定向 can be done in MVC 以及 URL Rewrite。


    因此,我的建议是为所有“重写”从 URL 重写切换到路由,因为路由不再真正需要这些。您可以设置一个类似于您的重写的configuration with routing 以访问您的.ashx 页面。

    routes.MapPageRoute(
        routeName: "RouteASHX",
        routeUrl: "{ashxPage}", 
        physicalFile: "~/{ashxPage}.ashx",
        checkPhysicalUrlAccess: false,
        defaults: new RouteValueDictionary(),
        constraints: new RouteValueDictionary(new { ashxPage = @"customers|orders|products.*" }));
    

    如果 Web API 请求与 URL 重写条件匹配(例如,CustomerController 中的无参数 api/v2/customers 有效,因为它匹配 &lt;match url="(customers|orders|products.*)"/&gt;,但 api/v2/customers/C123 失败,因为它匹配不符合重写条件)。

    这是另一个不相关的问题,这是由于使用具有相似路径和未定义顺序的属性路由。属性路由的一个问题是 .NET 属性根据定义具有未定义的顺序。另一方面,路由设置为first match always wins。这两个目标是矛盾的,这就是你被咬的地方。详情请见Attribute vs Conventional Routing

    幸运的是,修复起来并不难。您可以设置一个Order 属性来手动覆盖应用.NET 属性的任意顺序,将更具体的路由放在不太具体的路由之前。

    public class CustomersController : ApiController
    {
        [Route("api/v2/customers", Order = 2)]
        [ResponseType(typeof(CustomerCollection))]
        public IHttpActionResult Get()
        {
            ...
        }
    
        [Route("api/v2/customers/{identifier}", Order = 1)]
        [ResponseType(typeof(Customer))]
        public IHttpActionResult Get(string identifier)
        {
            ...
        }
    }
    

    应用此配置将使您的 Web API 无需重写 URL 即可工作。

    【讨论】:

    • 这个解决方案非常适合我们。很好地指出隐藏的第二个错误并使用Route 属性上的Order 参数进行修复!谢谢!
    【解决方案2】:

    如果您确定您的 Web API 项目将只处理对“api/v2/...”的传入请求,那么您可以在顶部编写一条新规则来中断,

    <rule name="break" stopProcessing="true">
     <match url="^api/v2/(.*)" />
     <action type="None" />
    </rule>
    

    更多详情请见my blog post

    【讨论】:

    • 谢谢。我们最初尝试过这个,但假设因为 URL 重写发生在请求的操作链中“更高”,规则干扰了 Web API 端点(例如,/customers.ashxapi/v2/customers 端点。最终解决方案是卸载 URL Rewrite 并使用更现代的 URL 路由方法。
    猜你喜欢
    • 2015-06-01
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多