呼叫ASP.NET Web API不能傳送PUT/DELETE請求
理想的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 = "";
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
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/964/viewspace-2817877/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- SpringMVC中如何傳送GET請求、POST請求、PUT請求、DELETE請求。SpringMVCdelete
- 理解ASP.NET Core - 傳送Http請求(HttpClient)ASP.NETHTTPclient
- java傳送http請求JavaHTTP
- Postman傳送Post請求Postman
- 傳送GET請求 示例
- Java傳送Post請求Java
- 在ASP.NET Core中用HttpClient(三)——傳送HTTP PATCH請求ASP.NETHTTPclient
- 精講RestTemplate第5篇-DELETE、PUT等請求方法使用詳解RESTdelete
- 簡述六種請求方法,get、head、put、delete、post、options區別delete
- vue-cli3.x中使用axios傳送請求,配合webpack中的devServer編寫本地mock資料介面(get/post/put/delete)VueiOSWebdevServerMockdelete
- Spartacus payment types 在 checkout 步驟中傳送 HTTP put 請求的實現明細HTTP
- 使用Feign傳送HTTP請求HTTP
- 如何傳送請求以及AJAX
- python傳送HTTP POST請求PythonHTTP
- 封裝 PHP curl http 請求 (全) Composer 安裝 httpbuilder,支援 GET,POST,PUT,DELETE封裝PHPHTTPUIdelete
- Web Beacon 重新整理/關閉頁面之前傳送請求Web
- Postman傳送請求引數是Map格式的請求Postman
- Vue 使用 Axios 傳送請求的請求體問題VueiOS
- nodejs使用request傳送http請求NodeJSHTTP
- java傳送GET和post請求Java
- Python爬蟲(二)——傳送請求Python爬蟲
- Vue中封裝axios傳送請求Vue封裝iOS
- linux用curl傳送post請求Linux
- 記錄環信IM使用restful介面時遇到的傳送PUT請求失敗的問題REST
- shell指令碼:批次傳送curl請求指令碼
- 使用requests庫來傳送HTTP請求HTTP
- 使用Postman傳送POST請求的指南Postman
- java傳送get請求帶引數Java
- 以Raw的方式傳送POST請求
- file_get_contents傳送post請求
- jQuery裡如何使用ajax傳送請求jQuery
- vue中使用axios傳送ajax請求VueiOS
- httprequest- post- get -傳送請求HTTP
- react-fetch資料傳送請求React
- 首頁 使用axios 傳送ajax請求iOS
- 解析HTTP協議六種請求方法,get,head,put,delete,post有什麼區別HTTP協議delete
- RxHttp 一條鏈傳送請求之註解處理器 Generated API(四)HTTPAPI
- Go HTTP GET 請求可以傳送 body 嗎GoHTTP