Asp.net请求处理程序之异步HTTP处理程序IHttpAsyncHandler、IHttpModule
Asp.net为开发者提供了两个非常有用的请求处理程序,一个是IHttpHandler,另一个是IHttpModule,我们先介绍下IHttpModule
IHttpModule:提供模块初始化和处置事件以实现类。
首先,IHttpModule是在IHttpHandler之前执行的。我们先移步https://docs.microsoft.com/zh-cn/dotnet/api/system.web.ihttpmodule?redirectedfrom=MSDN&view=netframework-4.8看下微软官方的介绍,在这里我们可以了解到如何自定义IHttpModule以及如何注册自定义的HttpModule。https://docs.microsoft.com/en-us/previous-versions/aspnet/ms227673(v=vs.100)。
总结出来就两点,第一,定义一个类实现IHttpModule接口,二,在web.config中的添加配置注册模块
<configuration> <system.webServer> <modules> <add name="HelloWorldModule" type="HelloWorldModule"/> </modules> </system.webServer> </configuration>
<configuration> <system.web> <httpModules> <add name="HelloWorldModule" type="HelloWorldModule"/> </httpModules> </system.web> </configuration>
这里需要注意一点,使用那段配置,取决于部署时使用的集成模式还是经典模式,或者为了方便,两端都配置;
在Init方法中我们可以注册HttpApplication请求的处理事件。
// // 摘要: // ASP.NET 将 HTTP 标头发送到客户端之前发生。 public event EventHandler PreSendRequestHeaders; // // 摘要: // 在选择该处理程序对请求作出响应时发生。 public event EventHandler MapRequestHandler; // // 摘要: // 释放应用程序时发生。 public event EventHandler Disposed; // // 摘要: // 作为执行的 HTTP 管道链中的第一个事件发生,当 ASP.NET 的请求做出响应。 public event EventHandler BeginRequest; // // 摘要: // 当安全模块已建立的用户标识时出现。 public event EventHandler AuthenticateRequest; // // 摘要: // 当安全模块已建立的用户标识时出现。 public event EventHandler PostAuthenticateRequest; // // 摘要: // 安全模块已验证用户身份验证时发生。 public event EventHandler AuthorizeRequest; // // 摘要: // 当前请求的用户已被授权时发生。 public event EventHandler PostAuthorizeRequest; // // 摘要: // 当 ASP.NET 完成授权事件以便从缓存中,跳过的事件处理程序 (例如,一个页面或 XML Web 服务) 执行的请求提供服务的缓存模块时发生。 public event EventHandler ResolveRequestCache; // // 摘要: // ASP.NET 将绕过当前事件处理程序的执行,并允许缓存模块以处理从缓存请求时发生。 public event EventHandler PostResolveRequestCache; // // 摘要: // ASP.NET 将内容发送到客户端之前发生。 public event EventHandler PreSendRequestContent; // // 摘要: // 当 ASP.NET 已映射到相应的事件处理程序的当前请求时出现。 public event EventHandler PostMapRequestHandler; // // 摘要: // 当 ASP.NET 已完成处理的事件处理程序时发生 System.Web.HttpApplication.LogRequest 事件。 public event EventHandler PostLogRequest; // // 摘要: // 已释放与请求相关联的托管的对象时发生。 public event EventHandler RequestCompleted; // // 摘要: // 获取与当前的请求相关联的请求状态 (例如,会话状态) 时发生。 public event EventHandler PostAcquireRequestState; // // 摘要: // ASP.NET 开始执行事件处理程序 (例如,一个页面或 XML Web 服务) 之前发生。 public event EventHandler PreRequestHandlerExecute; // // 摘要: // 当 ASP.NET 事件处理程序 (例如,一个页面或 XML Web 服务) 完成执行时发生。 public event EventHandler PostRequestHandlerExecute; // // 摘要: // ASP.NET 完成执行所有请求事件处理程序后发生。 此事件会导致状态模块保存当前的状态数据。 public event EventHandler ReleaseRequestState; // // 摘要: // 当 ASP.NET 已完成执行所有请求事件处理程序和存储数据的请求状态时发生。 public event EventHandler PostReleaseRequestState; // // 摘要: // 当 ASP.NET 完成执行事件处理程序,以便让缓存模块存储将用于为从缓存中的后续请求提供服务的响应时发生。 public event EventHandler UpdateRequestCache; // // 摘要: // 当 ASP.NET 完成更新的缓存模块和存储用于为从缓存中的后续请求提供服务的响应时发生。 public event EventHandler PostUpdateRequestCache; // // 摘要: // ASP.NET 执行当前请求的任何日志记录之前发生。 public event EventHandler LogRequest; // // 摘要: // 当 ASP.NET 获取与当前的请求相关联的当前状态 (例如,会话状态)。 public event EventHandler AcquireRequestState; // // 摘要: // 作为执行的 HTTP 管道链中的最后一个事件发生,当 ASP.NET 的请求做出响应。 public event EventHandler EndRequest; // // 摘要: // 当引发未处理的异常时发生。 public event EventHandler Error;
通过这些我们可以实现以下功:
1、去除响应头部Server、X-Powered-By、X-AspNet-Version
2、实现自定义路由功能
3、实现User申请身份信息初始化
IHttpAsyncHandler:定义 HTTP 异步处理程序对象必须实现的协定
官方说明:https://docs.microsoft.com/zh-cn/dotnet/api/system.web.ihttpasynchandler?view=netframework-4.8
和HttpModule的定义相似,需要顶一个实现IHttpAsyncHandler接口的类,同时需要在Web.config中进行配置,和HttpModuo相同,根据部署时是集成模式还是经典模式配置的节点不同
<system.webServer> <handlers> <add name="Ajax" path="Ajax.aspx" verb="*" type="LJ.Web.Api.AjaxEntry,LJ.Web.Api" resourceType="Unspecified" preCondition="integratedMode" /> </handlers> </system.webServer>
<system.web> <httpHandlers> <add path="Ajax.aspx" verb="*" type="LJ.Web.Api.AjaxEntry,LJ.Web.Api" /> </httpHandlers> </system.web>
与IHttpHandler相比,支持异步处理请求。
// // 摘要: // 定义 HTTP 异步处理程序对象必须实现的协定。 public interface IHttpAsyncHandler : IHttpHandler { // // 摘要: // 启动异步 HTTP 处理程序调用。 // // 参数: // context: // System.Web.HttpContext 提供对内部服务器对象的引用的对象 (例如, Request, ,Response, ,Session, ,和 // Server) 用于处理 HTTP 请求。 // // cb: // System.AsyncCallback 调用异步方法调用完成时。 如果 cb 是 null, ,不会调用的委托。 // // extraData: // 处理请求所需的所有未知额外数据。 // // 返回结果: // System.IAsyncResult 包含有关状态的进程的信息。 IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData); // // 摘要: // 在进程结束时,提供了异步处理 End 方法。 // // 参数: // result: // System.IAsyncResult 包含有关状态的进程的信息。 void EndProcessRequest(IAsyncResult result); }
通过定义我们大致可以了解到,它的异步不是通过async、Task实现,是通过参数cb回调方法实现
// // 摘要: // 引用在相应异步操作完成时调用的方法。 // // 参数: // ar: // 异步操作的结果。 [ComVisible(true)] public delegate void AsyncCallback(IAsyncResult ar);
也就是说,如果我们要实现真正的异步,需要自行做处理。以下是我自己的实现:
public virtual IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) { var ar = new AsyncResult(context, cb, extraData); if (AllowDomain) { if (!AllowCrossDomainService.Authenticate(context)) { ar.Send("不允许的请求域名!"); return ar; } } if (context.Request.HttpMethod.ToUpper() != "OPTIONS") { ExecutionContext.SuppressFlow();//取消多线程上下文的流动(当前线程的上下文内容,不会Copy到其子线程中去)可提升线程切换性能 var ret = ThreadPool.QueueUserWorkItem((state) => { HttpContext.Current = ar.context; try { ScopedIoc.Resolve<IHttpContextAccessor>().HttpContext = context; ProcessRequest(ar); } catch (Exception ex) { EventBus.Trigger(this, new AbpHandledExceptionData(ex, ControllerContext?.Controller?.AbpSession)); ar.Send(ex.ToString()); } }); ExecutionContext.RestoreFlow(); if (!ret) { ar.Send(new ActionResult() { Status = false, Msg = "服务器繁忙,请稍后再试!", Error = "无可用队列", }); } } else { ar.Send(string.Empty); } return ar; }