【问题标题】:Is it possible to implement X-HTTP-Method-Override in ASP.NET MVC?是否可以在 ASP.NET MVC 中实现 X-HTTP-Method-Override?
【发布时间】:2010-10-02 19:47:16
【问题描述】:

我正在使用 ASP.NET MVC 实现一个 RESTful API 的原型,除了这里和那里的奇怪错误之外,我已经实现了我在开始时提出的所有要求,除了调用者能够使用 @ 987654321@自定义标头覆盖HTTP方法。

我想要的是以下请求...

GET /someresource/123 HTTP/1.1
X-HTTP-Method-Override: DELETE

...将被分派到实现DELETE 功能而不是该操作的GET 功能的控制器方法(假设有多个方法实现该操作,并且它们标记有不同的@987654325 @ 属性)。因此,鉴于以下两种方法,我希望将上述请求分派给第二种方法:

[ActionName("someresource")]
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult GetSomeResource(int id) { /* ... */ }

[ActionName("someresource")]
[AcceptVerbs(HttpVerbs.Delete)]
public ActionResult DeleteSomeResource(int id) { /* ... */ }

有人知道这是否可能吗?这样做需要做多少工作......?

【问题讨论】:

    标签: asp.net-mvc rest http-headers http-method


    【解决方案1】:

    您可以创建一个实现OnActionExecuting 的ActionFilter,它会在调用控制器操作之前触发。然后,您可以询问请求标头,并根据 X-HTTP-Method-Override 标头的值(如果存在)进行重定向。

    【讨论】:

    • 那时它不会已经为它认为要调用的操作完成了参数绑定吗?这些方法可能有不同的参数。我想也许我需要在调度者选择动作之前挂钩?
    【解决方案2】:

    X-HTTP-Method-Override 是自定义标头,您的 Web 容器很可能不支持。

    你是从网页调用这个吗?如果是这样,您可能应该使用XmlHttpRequest 和DELETE(或任何您想要的动词)。更好的是,使用 JS 框架为您完成繁重的工作。

    【讨论】:

    • 我不是在调用它,我正在实现它...我想让实现支持自定义标头。
    • 我不明白。如果你控制实现,你到底为什么不使用标准动词设计的 HTTP 呢?
    • 因为不幸的是,有些客户端、代理和防火墙不允许使用 GET 或 POST 以外的动词,因此有时人们需要能够使用 GET 伪造 DELETE,使用 POST 伪造 PUT。有点蹩脚,但大多数 RESTful 服务似乎都支持这个标头。
    • 将 GET 映射到其他任何东西都是危险的。 GET 应该没有副作用。我们应该只覆盖 POSTs
    【解决方案3】:

    我很惊讶这还没有被提及,但是 ASP.NET MVC 本身就支持 X-HTTP-Method-Override 并且至少从版本 2 开始就已经这样做了。无需编写自定义代码来处理这个。

    它的工作方式如下:

    在 AcceptVerbsAttribute 内部(也由 [HttpPut]、[HttpPost] 等代理),有一个 IsValidForRequest 方法。在该方法中,它使用 Request.GetHttpMethodOverride() 进行检查,该方法返回具有以下条件的正确覆盖的 HTTP 方法:

    • 仅在 POST 请求中支持覆盖。其他所有内容都将被忽略。
    • 如果 X-HTTP-Method-Override 值为 GET 或 POST,则会被忽略。这是有道理的,因为您永远不需要覆盖这些值。
    • 它在此优先级的以下位置查找 X-HTTP-Method-Override: 1) HTTP 标头 2) 表单体 3) 查询字符串

    如果你真的很好奇,下面是 GetHttpMethodOverride() 的样子(来自 MVC 3 的源代码):

    public static class HttpRequestExtensions {
        internal const string XHttpMethodOverrideKey = "X-HTTP-Method-Override";
    
        public static string GetHttpMethodOverride(this HttpRequestBase request) {
            if (request == null) {
                throw new ArgumentNullException("request");
            }
    
            string incomingVerb = request.HttpMethod;
    
            if (!String.Equals(incomingVerb, "POST", StringComparison.OrdinalIgnoreCase)) {
                return incomingVerb;
            }
    
            string verbOverride = null;
            string headerOverrideValue = request.Headers[XHttpMethodOverrideKey];
            if (!String.IsNullOrEmpty(headerOverrideValue)) {
                verbOverride = headerOverrideValue;
            }
            else {
                string formOverrideValue = request.Form[XHttpMethodOverrideKey];
                if (!String.IsNullOrEmpty(formOverrideValue)) {
                    verbOverride = formOverrideValue;
                }
                else {
                    string queryStringOverrideValue = request.QueryString[XHttpMethodOverrideKey];
                    if (!String.IsNullOrEmpty(queryStringOverrideValue)) {
                        verbOverride = queryStringOverrideValue;
                    }
                }
            }
            if (verbOverride != null) {
                if (!String.Equals(verbOverride, "GET", StringComparison.OrdinalIgnoreCase) &&
                    !String.Equals(verbOverride, "POST", StringComparison.OrdinalIgnoreCase)) {
                    incomingVerb = verbOverride;
                }
            }
            return incomingVerb;
        }
    }
    

    【讨论】:

      【解决方案4】:

      这个对话有点老了,但我想分享一下我使用 mvc 2 的发现:

      浏览器支持两种 HTTP 动词:GET 和 POST,但 ASP.NET MVC 2 允许您使用 Html.HttpMethodOverride 辅助方法模拟 Put、Get 和 Delete。在内部,这是通过在 X-HTTP-Method-Override 表单字段中发送动词来实现的。 [AcceptVerbs] 属性以及新的较短动词属性使用 HttpMethodOverride 的行为:

      例如动作声明:

      [ActionName("someresource")]
      [HttpDelete]
      public ActionResult DeleteSomeResource()
      

      应对您的将 X-HTTP-Method-Override 设置为 Delete 的 get 请求负责。

      【讨论】:

      • 不只是在表单域中。也可以在标题或查询字符串中。这个想法是支持 HTTP 方法覆盖。 +1
      【解决方案5】:

      插入表格:

      <%= Html.HttpMethodOverride(HttpVerbs.Delete) %>
      

      【讨论】:

        【解决方案6】:

        你看过Simply Restful Routing吗?它已经这样做了。

        于 2010 年 2 月编辑添加:方法覆盖内置于 MVC 2 中。

        【讨论】:

        • 我没有看到任何关于它实现 X-HTTP-Method-Override 的信息,快速扫描源代码也没有发现任何问题。你确定吗?如果是这样,你能指出我在其中实现它的文件吗?干杯!
        • X-HTTP-Method-Override 是一个人为支持非 GET/POST 请求而设计的。简单的 Restful Routing 是另一个。不同的设计,相同的目标。
        • 我真的不想将 REST 与 RPC 样式的 URL 结合起来(我对其中一个很满意,但更愿意避免两者的结合)所以我想我宁愿去使用 header 选项而不是使用简单 Restful 设计中的操作链接。
        【解决方案7】:

        Levi 的回答很棒。此外,我在自定义 AcceptsVerbsAttribute 中添加了一个检查,该检查还检查 FORM 集合,因此您可以简单地放置一个隐藏输入来触发 DELETE(类似于 MVC 2 的Html.HttpMethodOverride(HttpVerbs.Delete))。

        <input name="X-HTTP-Method-Override" type="hidden" value="DELETE" />
        

        将incomingVerb分配改为:

        string incomingVerb = controllerContext.HttpContext.Request.Headers["X-HTTP-Method-Override"] ?? controllerContext.HttpContext.Request.Form["X-HTTP-Method-Override"] ??controllerContext.HttpContext.Request.HttpMethod;
        

        小心这种方法!请参阅 Stephen Walther 的 related post。

        希望这对某人有所帮助。

        【讨论】:

        • 另一种可能的解决方案,将其作为 MIME 类型参数在 content-type 标头中发送。
        【解决方案8】:

        您将无法按原样使用 [AcceptVerbs] 属性,因为它与请求的实际 HTTP 动词相关联。幸运的是 [AcceptVerbs] 属性非常简单;你可以在http://www.codeplex.com/aspnet/SourceControl/changeset/view/21528#266431查看源代码。

        简而言之,子类 AcceptsVerbsAttribute 并覆盖 IsValidForRequest() 方法。实现将类似于以下内容:

        string incomingVerb = controllerContext.HttpContext.Request.Headers["X-HTTP-Method-Override"] ?? controllerContext.HttpContext.Request.Method;
        return Verbs.Contains(incomingVerb, StringComparer.OrdinalIgnoreCase);
        

        【讨论】:

        • 我不得不从 AcceptVerbsAttribute 中截取代码并实现我自己的代码,因为不幸的是它被密封了,但是这种方法非常有效,而且很好而且简单,所以看起来你得到了 300 分!
        • hi levi,但是我的 ASP.net IIS 或 MVC 拒绝 DELETE 和 PUT 请求,有什么办法可以完成这项工作吗?我试图将 Allow: PUT, DELETE 放入 IIS Allow 标头,但它不起作用...
        • Duc,我知道这已经很久很久了,但是看看是否安装了 WebDav。如果是,请卸载它。否则,它将拦截您的 PUT 和 DELETE 请求。
        猜你喜欢
        • 2010-12-21
        • 1970-01-01
        • 2014-12-28
        • 1970-01-01
        • 1970-01-01
        • 2019-11-14
        • 2011-05-11
        • 2011-03-18
        • 1970-01-01
        相关资源
        最近更新 更多