如果调用ASP.NET Web API不能发送PUT/DELETE请求怎么办?

时间:2022-10-26 19:40:22

理想的RESTful Web API采用面向资源的架构,并使用请求的HTTP方法表示针对目标资源的操作类型。但是理想和现实是有距离的,虽然HTTP协议提供了一系列原生的HTTP方法,但是在具体的网络环境中,很多是不支持的。比如有的浏览器只能发送GET和POST请求,客户端发送的PUT请求也不一定能够被服务器理解。除了客户端和服务器对请求采用的HTTP方法的制约外,像代理(Proxy)、网关(Gateway)等这些中间部件都具有针对HTTP方法的限制。[本文已经同步到《How ASP.NET Web API Works?》]

我们一般采用“HTTP方法重写”的方式来解决这个问题。具体来说,Web API依然针对标准HTTP方法具有的资源操作语义来定义。客户端发送的请求只能采用网络允许的HTTP方法(一般来说,GET和POST总是被支持的),但是与资源操作方式相匹配的HTTP方法名称会通过一个请求报头发送给服务器。服务器在根据请求实施操作选择之前,它会提取该请求报头携带的HTTP方法,请求自身的HTTP方法会被它重写或者覆盖。按照约定,我们将这个携带“覆盖当前请求HTTP方法”的报头命名为“X-HTTP-Method-Override”。

ASP.NET Web API采用管道式的设计,这个旨在解决部分HTTP方法在网络环境中不被支持的HTTP方法重写机制可以很容易地通过自定义HttpMessageHandler来实现。具体来说,由于消息处理管道根据表示请求的HttpRequestMessage对象的Method属性确定请求采用的HTTP方法,并且这是一个可读写的属性,如果我们利用注册的HttpMessageHandler根据“X-HTTP-Method-Override”报头值来设置当前HttpRequestMessage的Method属性,那么管道后续部分将会针对这个覆盖的HTTP方法进行处理。

为此我们定义了如下一个HttpMethodOverrideHandler类型,它继承自DelegatingHandler。我们在重写的SendAsync方法中实现了对“X-HTTP-Method-Override”报头的提取和对HTTP方法的重写,最后调用基类的同名方法将处理后的请求传递给后续的HttpMessageHandler。

   1: public class HttpMethodOverrideHandler: DelegatingHandler

   2: {

   3:     protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)

   4:     {            

   5:         IEnumerable<string> methodOverrideHeader;

   6:         if (request.Headers.TryGetValues("X-HTTP-Method-Override", out methodOverrideHeader))

   7:         {

   8:             request.Method = new HttpMethod(methodOverrideHeader.First());

   9:         }

  10:         return base.SendAsync(request, cancellationToken);

  11:     }

  12: }

我们在一个空ASP.NET Web API应用中定义了如下一个继承自ApiController的DemoController,并在其中定义了4个用于返回自身方法名称的Action方法(Get、Post、Put和Delete)。按照ASP.NET Web API默认提供的HTTP方法与Action方法名称之间的映射机制,这4个Action方法支持HTTP方法与自身的方法名称一致。

   1: public class DemoController : ApiController

   2: {

   3:     public string Get()

   4:     {

   5:         return "Get";

   6:     }

   7:  

   8:     public string Post()

   9:     {

  10:         return "Post";

  11:     }

  12:  

  13:     public string Put()

  14:     {

  15:         return "Put";

  16:     }

  17:  

  18:     public string Delete()

  19:     {

  20:         return "Delete";

  21:     }

  22: }

在Global.asax文件中,我们采用如下的代码将一个HttpMethodOverrideHandler对象注册到ASP.NET Web API的消息处理管道中。我们采用IIS Express作为宿主,并将采用的端口固定为“3721”。

   1: public class WebApiApplication : System.Web.HttpApplication

   2: {

   3:     protected void Application_Start()

   4:     {

   5:         GlobalConfiguration.Configuration.MessageHandlers.Add(new HttpMethodOverrideHandler());

   6:         //其他操作

   7:     }

   8: }

我们创建一个控制台应用作为调用Web API的客户端程序。如下面的代码片断所示,我们定义了一个辅助方法InvokeWebApi根据提供的HttpClient对象和请求采用的HTTP方法进行Web API的调用。在该方法中,我们根据指定的HTTP方法创建了一个指向目标Web API的HttpRequestMessage对象,并将其作为参数调用HttpClient对象的SendAsync方法对目标Web API发起调用。Web API成功调用后会得到最终被执行的目标Action方法的名称,我们将它连同当前请求采用的HTTP方法和“X-HTTP-Method-Override”报头值打印在控制台上。

   1: class Program

   2: {

   3:     static void Main(string[] args)

   4:     {

   5:         HttpClient httpClient1 = new HttpClient();

   6:         HttpClient httpClient2 = new HttpClient();

   7:         HttpClient httpClient3 = new HttpClient();

   8:         HttpClient httpClient4 = new HttpClient();

   9:  

  10:         httpClient3.DefaultRequestHeaders.Add("X-HTTP-Method-Override", "PUT");

  11:         httpClient4.DefaultRequestHeaders.Add("X-HTTP-Method-Override", "DELETE");

  12:  

  13:         Console.WriteLine("{0,-7}{1,-24}{2,-6}", "Method", "X-HTTP-Method-Override", "Action");

  14:         InvokeWebApi(httpClient1, HttpMethod.Get);

  15:         InvokeWebApi(httpClient2, HttpMethod.Post);

  16:         InvokeWebApi(httpClient3, HttpMethod.Post);

  17:         InvokeWebApi(httpClient4, HttpMethod.Post);

  18:  

  19:         Console.Read();

  20:     }

  21:  

  22:     async static void InvokeWebApi(HttpClient httpClient, HttpMethod method)

  23:     {

  24:         string requestUri = "http://localhost:3721/api/demo";

  25:         HttpRequestMessage request = new HttpRequestMessage(method, requestUri);

  26:         HttpResponseMessage response = await httpClient.SendAsync(request);

  27:         IEnumerable<string> methodsOverride;

  28:         httpClient.DefaultRequestHeaders.TryGetValues("X-HTTP-Method-Override", out methodsOverride);

  29:         string actionName = response.Content.ReadAsStringAsync().Result;

  30:         string methodOverride = methodsOverride == null ? "N/A" : methodsOverride.First();

  31:         Console.WriteLine("{0,-7}{1,-24}{2,-6}", method, methodOverride, actionName.Trim('"'));

  32:     }

  33: }

在Main方法中,我们创建了4个HttpClient对象(httpClient1、httpClient2、httpClient3和httpClient4),并将“X-HTTP-Method-Override”报头添加到httpClient3和httpClient4的默认报头集合中,指定的HTTP方法分别是“PUT”和“DELETE”。我们将这4个HttpClient对象作为参数调用辅助方法InvokeWebApi对目标Web API发起4次调用,除了第1次(由于InvokeWebApi是一个异步方法,代码中的第一次调用并不意味着它首先被执行,更不能确保针对它的Web API调用率先完成)采用GET请求之外,其余请求均采用POST方法。

在启动Web API宿主程序后运行客户端控制台应用,我们会得到如下所示的输出结果。我们可以清楚地看到在请求不具有“X-HTTP-Method-Override”报头的情况下,执行的Action方法取决于请求采用的HTTP方法。反之,如果请求通过“X-HTTP-Method-Override”报头携带了相应的HTTP方法,它将用于目标Action方法的选择。这一切均是HttpMethodOverrideHandler这个自定义HttpMessageHandler的功劳。

   1: Method X-HTTP-Method-Override  Action

   2: POST   PUT                     Put

   3: GET    N/A                     Get

   4: POST   N/A                     Post

   5: POST   DELETE                  Delete

如果调用ASP.NET Web API不能发送PUT/DELETE请求怎么办?的更多相关文章

  1. 如果调用&period;net core Web API不能发送PUT&sol;DELETE请求怎么办?

    通过阅读大佬的文章 http://www.cnblogs.com/artech/p/x-http-method-override.html想到的 通过注册中间件来解决这个问题 public void ...

  2. MVC项目实践&comma;在三层架构下实现SportsStore-09&comma;ASP&period;NET MVC调用ASP&period;NET Web API的查询服务

    ASP.NET Web API和WCF都体现了REST软件架构风格.在REST中,把一切数据视为资源,所以也是一种面向资源的架构风格.所有的资源都可以通过URI来唯一标识,通过对资源的HTTP操作(G ...

  3. 通过HttpClient 调用ASP&period;NET Web API

    在前面两篇文章中我们介绍了ASP.NET Web API的基本知识和原理,并且通过简单的实例了解了它的基本(CRUD)操作.我们是通过JQuery和Ajax对Web API进行数据操作.这一篇我们来介 ...

  4. 如何通过js跨域调用ASP&period;NET Web API (请问如何实现在javascript中通过http get的方式跨域调用ASP&period;NET Web API?)

    客户端js无需任何专门设置,使用通常的ajax调用即可: $.ajax({ url: '跨域URL', type: 'get', dataType: 'json', success: function ...

  5. How ASP&period;NET Web API 2&period;0 Works&quest;&lbrack;持续更新中…&rsqb;

    一.概述 RESTful Web API [Web标准篇]RESTful Web API [设计篇] 在一个空ASP.NET Web项目上创建一个ASP.NET Web API 2.0应用 二.路由 ...

  6. ASP&period;NET Web API标准的&ldquo&semi;管道式&rdquo&semi;设计

    ASP.NET Web API的核心框架是一个消息处理管道,这个管道是一组HttpMessageHandler的有序组合.这是一个双工管道,请求消息从一端流入并依次经过所有HttpMessageHan ...

  7. Self Host模式下的ASP&period; NET Web API是如何进行请求的监听与处理的?

    构成ASP.NET Web API核心框架的消息处理管道既不关心请求消息来源于何处,也不需要考虑响应消息归于何方.当我们采用Web Host模式将一个ASP.NET应用作为目标Web API的宿主时, ...

  8. 使用ASP&period;NET web API创建REST服务&lpar;二&rpar;

    Creating a REST service using ASP.NET Web API A service that is created based upon the architecture ...

  9. 使用ASP&period;NET web API创建REST服务&lpar;三&rpar;

    本文档来源于:http://www.cnblogs.com/madyina/p/3390773.html Creating a REST service using ASP.NET Web API A ...

随机推荐

  1. 成功进行了一次UDP打洞

    本次测试参数:服务端是公网固定IP:两个客户端A和B分别位于不同电脑,不同宽带,不同型号路由后面(一个家庭路由,一个企业路由),且路由没有经过特别的设置.测试没有什么特别的地方,只是依照网络资料进行实 ...

  2. JAVA内存管理

    java与c++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙.墙外面的人想进去,墙里面的人想出去. 1.java内存分布 程序计数器 栈(局部变量.操作数.动态链接.方法出口) 每一个方法从调用 ...

  3. SSH原理与运用(二):远程操作与端口转发

    SSH原理与运用(二):远程操作与端口转发 作者:阮一峰 (Image credit: Tony Narlock) 七.远程操作 SSH不仅可以用于远程主机登录,还可以直接在远程主机上执行操作. 上一 ...

  4. ListView配合BaseAdapter

    BaseAdapter使用比较麻烦,它是个抽象类,需要重写4个方法分别是getCount() getItem(..) getItemId(..) getVew(..),相应的使用BaseAdapter ...

  5. GO语言练习ONE

  6. 打开另外一个App

    /** * 打开一个app * * @param packageName * @param data * @return */ public static boolean lanuchApp(Cont ...

  7. vue中input输入框的模糊查询实现

    最近在使用vue写webapp在,一些感觉比较有意思的分享一下. 1:input输入框: <input class="s-search-text" placeholder=& ...

  8. &lbrack;EOJ Monthly 2018&period;10&rsqb;&lbrack;C&period; 痛苦的 01 矩阵&rsqb;

    题目链接:C. 痛苦的 01 矩阵 题目大意:原题说的很清楚了,不需要简化_(:з」∠)_ 题解:设\(r_i\)为第\(i\)行中0的个数,\(c_j\)为第\(j\)列中0的个数,\(f_{i,j ...

  9. numpy和matplotlib

    Python的科学计算包 – Numpy numpy(Numerical Python extensions)是一个第三方的Python包,用于科学计算.这个库的前身是1995年就开始开发的一个用于数 ...

  10. Java ——基础语法

    package myhello; // 本类所在的包的路径 import af.util.AfMath; // 导入对应的类 import java.util.Random; // 导入随机数的类 p ...