【乾貨】.NET WebApi HttpMessageHandlerg管道
訊息攔截器是一個類,接收 HTTP request並返回 HTTP response,Message handler 繼承自抽象類 HttpMessageHandler,那麼學習訊息過濾器之前你應該瞭解下webapi的執行流程。
以上是webapi的執行流程,先是從response開始執行一套順序之後通過network再回到了Request,其中經過了messageHandler,因為它是webapi架構中給我們可以自定義handler的地方,這和以往的webform差不多。都是基於http請求的。
有可能你會說這和過濾器Aop模式差不多啊,但你可以看完這篇文章之後再比比誰強大,當然它兩者的用處都不同。
那訊息攔截器有什麼用呢,聽名字我覺得你應該就知道是怎麼回事,它是可以在客戶端請求用修改請求資訊的中間層,再次其中我們可以修改;新增 response headers,在到達 controller 之前,進行引數驗證!
自定義 MessageHandler 需要繼承 System.Net.Http.DelegatingHander
並且過載 SendAsync 方法
public class MessageHandler1 : DelegatingHandler { protected async override Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { Debug.WriteLine("hello"); var response = await base.SendAsync(request, cancellationToken); Debug.WriteLine("bye"); return response; } }
這是最基本的處理流程,當然自此期間你需要去新增配置。
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MessageHandlers.Add(new MessageHandler1());
config.MessageHandlers.Add(new MessageHandler2());
}
}
在訊息攔截器中常見的是要判斷使用者資訊,因為像ActionFilterAttribute、ApiControllerActionInvoker、ExceptionFilterAttribute 這些都是在action之前的,那我們就要在之前進行判斷。
在HttpRequestMessage中包含了以下屬性,這些你都是可以改的。
如何操作header?
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
response.Headers.Add("X-Custom-Header", "This is my custom header.");
return response;
}
首先呼叫sendAsync將請求傳遞給inner handler,讓它返回響應資訊,但是它在建立非同步的時候,響應訊息是不可用的。
只能全域性去配置嗎?
//路由中指定Message Handler
config.Routes.MapHttpRoute(
name: "Route2",
routeTemplate: "api2/{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
handler: new MessageHandler2() // per-route message handler
);
這時MessageHandler2替換預設的HttpControllerDispatcher。這個栗子中MessageHandler2建立響應,匹配“Route2”的請求永遠不會轉到控制器。這使我們可以使用自己的自定義響應替換整個Web API控制器機制。
不知道你有沒有想過,如果你的webapi不支援一些特殊的請求,你該怎麼辦呢,這個時候呵呵,你應該知道了吧!
在這個例項中我們定義了一個集合,在post請求中,一定不是get,那麼就有可能是put 或者delete等待的請求頭,那麼我們可以獲取進行修改。
public class MethodOverrideHandler : DelegatingHandler
{
readonly string[] _methods = { "DELETE", "HEAD", "PUT" };
const string _header = "X-HTTP-Method-Override";
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.Method == HttpMethod.Post && request.Headers.Contains(_header))
{
var method = request.Headers.GetValues(_header).FirstOrDefault();
if (_methods.Contains(method, StringComparer.InvariantCultureIgnoreCase))
{
request.Method = new HttpMethod(method);
}
}
return base.SendAsync(request, cancellationToken);
}
}
那我們可以獲取請求頭,如何進行新增呢??
public class CustomHeaderHandler : DelegatingHandler
{
async protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
response.Headers.Add("X-Custom-Header", "This is my custom-header.");
return response;
}
}
在以上程式碼中我們通過base.SendAsync呼叫內部訊息處理器返回相應結果,base.SendAsync之前是不可響應獲取訊息的。
這個示例使用了await關鍵字,以便在SendAsync完成之後非同步地執行任務。
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
return base.SendAsync(request, cancellationToken).ContinueWith(
(task) =>
{
HttpResponseMessage response = task.Result;
response.Headers.Add("X-Custom-Header", "This is my custom header.");
return response;
}
);
}