是否可以在ASP.NET MVC中实现X-HTTP-Method-Override?

时间:2009-01-21 23:41:24

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

我正在使用ASP.NET MVC实现RESTful API的原型,除了奇怪的bug之外,我已经实现了我在开始时提出的所有要求,除了调用者能够使用{ {1}}自定义标头覆盖HTTP方法。

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

X-HTTP-Method-Override

...将被调度到我的控制器方法,该方法实现GET /someresource/123 HTTP/1.1 X-HTTP-Method-Override: DELETE 功能而不是该操作的DELETE功能(假设有多个方法实现该操作,并且它们已被标记具有不同的GET属性)。因此,考虑到以下两种方法,我希望将上述请求分派到第二个方法:

[AcceptVerbs]

有人知道这是否可行?这样做会有多少工作......?

8 个答案:

答案 0 :(得分:5)

您将无法按原样使用[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);

答案 1 :(得分:3)

列维的回答很棒。另外,我在自定义的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

希望这有助于某人。

答案 2 :(得分:3)

插入表单:

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

答案 3 :(得分:2)

这次谈话有点旧,但我想用mvc 2分享我发现的内容:

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

例如,行动声明:

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

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

答案 4 :(得分:1)

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

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

答案 5 :(得分:1)

我很惊讶这还没有被提及,但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;
    }
}

答案 6 :(得分:0)

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

你是从网页上调用的吗?如果是这样,您应该将XmlHttpRequestDELETE(或您想要的任何动词)一起使用。更好的是,使用JS框架为您做繁重的工作。

答案 7 :(得分:0)

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