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

发布于 2024-07-12 10:13:32 字数 726 浏览 6 评论 0原文

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

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

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

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

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

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

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

I'm implementing a prototype of a RESTful API using ASP.NET MVC and apart from the odd bug here and there I've achieve all the requirements I set out at the start, apart from callers being able to use the X-HTTP-Method-Override custom header to override the HTTP method.

What I'd like is that the following request...

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

...would be dispatched to my controller method that implements the DELETE functionality rather than the GET functionality for that action (assuming that there are multiple methods implementing the action, and that they are marked with different [AcceptVerbs] attributes). So, given the following two methods, I would like the above request to be dispatched to the second one:

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

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

Does anybody know if this is possible? And how much work would it be to do so...?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

蘑菇王子 2024-07-19 10:13:33

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

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

The X-HTTP-Method-Override is a custom header and most likely isn't supported by your web container.

Are you calling this from a web page? If so, you should probably use XmlHttpRequest with DELETE (or whatever verb you want). Better yet, use a JS framework to do the heavy lifting for you.

小瓶盖 2024-07-19 10:13:33

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

You could create an ActionFilter that implements OnActionExecuting, which fires before the controller action is invoked. You could then interrogate the request headers, and redirect based on the value of the X-HTTP-Method-Override header, when present.

空名 2024-07-19 10:13:32

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

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

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

You won't be able to use the [AcceptVerbs] attribute as-is since it's tied to the request's actual HTTP verb. Fortunately the [AcceptVerbs] attribute is very simple; you can see the source for yourself at http://www.codeplex.com/aspnet/SourceControl/changeset/view/21528#266431.

In short, subclass AcceptsVerbsAttribute and override the IsValidForRequest() method. The implementation would be something like the following:

string incomingVerb = controllerContext.HttpContext.Request.Headers["X-HTTP-Method-Override"] ?? controllerContext.HttpContext.Request.Method;
return Verbs.Contains(incomingVerb, StringComparer.OrdinalIgnoreCase);
烟火散人牵绊 2024-07-19 10:13:32

莱维的回答很棒。 此外,我在自定义 AcceptsVerbsAttribute 中添加了一个检查,它还检查 FORM 集合,因此您只需放置一个隐藏输入即可触发 DELETE(类似于 MVC 2 的 Html.HttpMethodOverride(HttpVerbs.Delete)) 。

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

将传入动词分配更改为:

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

小心这种方法! 请参阅 相关帖子

希望这对某人有帮助。

Levi's answer is great. Additionally, I added a check in the custom AcceptsVerbsAttribute that also examines the FORM collection, so you can simply put a hidden input to trigger the DELETE (similar to MVC 2's Html.HttpMethodOverride(HttpVerbs.Delete)).

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

Change the incomingVerb assignment to:

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

Be careful with this approach! See a related post by Stephen Walther.

Hopefully this helps someone.

凉世弥音 2024-07-19 10:13:32

插入表格:

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

Insert to Form:

<%= Html.HttpMethodOverride(HttpVerbs.Delete) %>
巴黎盛开的樱花 2024-07-19 10:13:32

这个对话有点老了,但我想分享我使用 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”的 get 请求负责。

This conversation is a bit old, but I wanted to share what I have found using mvc 2:

Browsers support two HTTP verbs: GET and POST, but ASP.NET MVC 2 allows you to simulate Put, Get, and Delete using Html.HttpMethodOverride helper method. Internally, this works by sending the verb in an X-HTTP-Method-Override form field. The behavior of HttpMethodOverride is used by the [AcceptVerbs] attribute as well as the new shorter verb attributes:

For example, the action declaration:

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

should take responsibility for your get request that has the X-HTTP-Method-Override set to Delete.

孤蝉 2024-07-19 10:13:32

令我惊讶的是,这一点尚未被提及,但 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;
    }
}

I'm surprised that this hasn't been mentioned yet, but ASP.NET MVC natively supports X-HTTP-Method-Override and has been doing so from at least version 2. There's no need to write custom code to handle this.

It work in the following way:

Inside AcceptVerbsAttribute (also proxied by [HttpPut], [HttpPost], etc), there's an IsValidForRequest method. Inside that method, it checks with Request.GetHttpMethodOverride(), which returns the proper overriden HTTP method with the following conditions:

  • Overriding is only supported in POST requests. All others are ignored.
  • If the X-HTTP-Method-Override value is GET or POST, it's ignored. This makes sense, as you'd never need to override with these values.
  • It looks for X-HTTP-Method-Override in the following places in this priority:
    1) HTTP Header
    2) Form Body
    3) Query String

If you're really curious, here's how GetHttpMethodOverride() looks (from MVC 3's source code):

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;
    }
}
你怎么这么可爱啊 2024-07-19 10:13:32

您是否看过简单的静态路由? 它已经这样做了。

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

Have you looked at Simply Restful Routing? It already does this.

Edited Feb 2010 to add: Method overrides are built into MVC 2.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文