ASP.NET Core管道深度剖析(1):采用管道处理HTTP请求

之所以称ASP.NET
Core是一个Web开发平台,源于它具有一个极具扩展性的请求处理管道,我们可以通过这个管道的定制来满足各种场景下的HTTP处理需求。ASP.
NET Core应用的很多特性,比如路由、认证、会话、缓存等,也同时定制消息处理管道来实现的。我们甚至可以通过管道定制在ASP.NET
Core平台上创建我们自己的Web框架,实际上MVC和SingalR这两个重要的Web框架也是采用这样的方式创建的。

HTTP协议自身的特性决定了任何一个Web应用的工作方式都是监听、接收并处理HTTP请求,并在最终对请求予以响应,HTTP请求处理是管道式设计典型的应用场景。我们根据HTTP请求的处理流程定制出一个消息处理管道,让接收到的HTTP请求消息想水一样流入这个管道,组成这个管道的各个环节一次对它作相应的处理。处理的结果同样转变成消息逆向流入这个管道进行处理,并最终转变成回复给客户端的HTTP响应。ASP.NET

Core的消息处理管道从设计的角度来讲是非常简单的,但是从具体实现的角度则相对难以理解,为了让读者朋友们通过本章对此具有深刻的理解,我们从简单的部分讲起。

一、从Hello World说起

为了使读者朋友们能够以最直观的感受认识ASP.NET
Core的消息处理管道,我们来创建一个最简单的Hello
World程序。这是一个仅仅由两个类型构成的控制台程序,作为程序入口的Main方法定义在Program类中,Startup则作为初始化类型。这个程序被启动之后将会绑定到默认端口5000进行HTTP请求的监听,任何针对基地址
“http://localhost:5000/” 的请求后,该程序都将响应 “Hello World” 。

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         new WebHostBuilder()
   6:             .UseKestrel()
   7:             .UseStartup<Startup>
   8:             .Build()
   9:             .Start();
  10:     }
  11: }
  12:  
  13:  
  14: public class Startup
  15: {
  16:     public void Configure(IApplicationBuilder app)
  17:     {
  18:         app.Run(context=>context.Response.WriteAsync("Hello World");
  19:     }
  20: }

这个程序涉及到一个重要的对象WebHost,它通过WebHostBuilder的Build方法创建。WebHost可以看成是Web应用的宿主,启动Web应用本质上就是启动它的宿主。当我们调用WebHost的Start方法启动应用的时候,用于监听、接收、处理和响应HTTP请求的消息处理管道随之被建立。那么在这个过程中,通过调用UseStartup<T>方法注册到WebHostBuilder上的初始化类型将用来对这个管道进行定制。总的来说,ASP.NET
Core的请求处理管道由WebHost在启动的时候构建,WebHostBuilder则是后者的创建者,右图揭示了三者之间的关系。

二、管道的构成

HTTP请求处理流程始于对请求的监听与接收,终于对请求的响应,这两项工作由同一个对象来完成,我们称之为 “服务器(Server)”
,尽管ASP.NET Core的请求处理管道可以被自由地订制,但是该管道必须有一个服务器,服务器是整个管道的 “龙头”
。在上面的这个Hello
World应用中,在调用WebHostBuilder的Build方法创建一个WebHost之前,我们调用了它的一个扩展方法UseKestrel,这个方法的作用就是为后续构建的管道注册一个名为KestrelServer的服务器。

随着WebHost的Start方法的调用,按照具体需求进行定制的请求处理管道被构建出来,作为第一个节点的服务器会绑定到一个预设的端口(比如KestrelServer默认采用5000作为监听端口)开始监听来自客户端的HTTP请求。一旦请求抵达,服务器会接收请求并将其标准化后向管道后续的节点进行转发,我们将管道中位于服务器之后的请求处理节点成为“中间件(Middleware)”。每个中间件都具有各自独立的功能,比如我们有专门实现路由功能的中间件,由专门实施用户认证的中间,所谓的对请求处理管道的定制体现在根据具体的需求选择对应的中间件组成最终处理请求的管道。左图揭示了由一个服务器和一组中间件构成的请求处理管道。

一个建立在ASP.NET Core之上的应用一般都是根据某个框架开发的,开发框架基本上是建立在某个特殊的中间件上。以ASP.NET
Core MVC这个最著名的框架为例,它实际上是利用一个叫做 “路由”
的中间件实现了请求地址与Controller/Action之间的映射,并在此基础实现了激活Controller、执行Action以及呈现View等一系列的功能。所以应用程序可以视为某个中间件的一部分,如果一定要将它独立出来,整个请求处理管道将呈现出如右图所示的结构。

三、管道的定制

在演示的Hello World程序中,我们在调用WebHostBuilder的Build方法创建WebHost之前先调用了它的扩展方法UseStartup<T>方法注册了一个类型为Startup的启动类型。从请求处理管道的角度来讲,注册的这个启动类型的目的在于对构建的管道进行定制,说得更加具体一点,我们利用这个类型为管道注册需要的中间件。一般来说,被注册的启动类型必须具有一个类似于下面代码片断所示的Configure方法,这个方法可以是静态方法和也可以实例方法。这个方法的参数并没有严格的限制,但是第一个参数类型必须是IApplicationBuilder接口。

   1: public class Startup
   2: {
   3:     public void Configure(IApplicationBuilder app);
   4: }

对中间件的注册就是实现在这样一个Configure方法之中。在演示的实例中,我们调用了IApplicationBuilder接口的扩展方法Run注册了一个中间件,它承载的请求处理逻辑很简单,即使直接响应一个“Hello

World”字符串。在真实的项目中,我们会根据具体的应用场景在这样一个方法中利用ApplicationBuilder注册相应的中间件进而构建一个适合当前请求处理需求的管道。

   1: public class Startup
   2: {
   3:     public void Configure(IApplicationBuilder app)
   4:     {
   5:         app.UseExceptionHandler("/Home/Error");
   6:         app.UseStaticFiles();
   7:         app.UseIdentity();           
   8:  
   9:         app.UseMvc();
  10:     }
  11: }

比如在一个ASP.NET Core
MVC应用中我们除了按照如上的方式调用扩展方法UseMvc注册了支撑MVC框架的中间件(实际上是一个实现路由的中间件)之外,我们还通过调用其它的扩展方法注册了相应的中间件实现了对静态文件的访问(UseStaticFiles)、错误页面的呈现(UseExceptionHandler)以及基于ASP.NET
Identity Framework的认证(UseIdentity)。

 



一、采用管道处理HTTP请求
二、创建一个“迷你版”的管道来模拟真实管道请求处理流程
三、管道如何处理HTTP请求的
四、管道是如何被创建出来的

作者:蒋金楠
微信公众账号:大内老A
微博:www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

原文链接

时间: 2024-11-17 02:34:11

ASP.NET Core管道深度剖析(1):采用管道处理HTTP请求的相关文章

ASP.NET Core管道深度剖析(2):创建一个“迷你版”的管道来模拟真实管道请求处理流程

从<ASP.NET Core管道深度剖析(1):采用管道处理HTTP请求>我们知道ASP.NET Core请求处理管道由一个服务器和一组有序的中间件组成,所以从总体设计来讲是非常简单的,但是就具体的实现来说,由于其中涉及很多对象的交互,我想很少人能够地把它弄清楚.如果想非常深刻地认识ASP.NET Core的请求处理管道,可以分两个步骤来进行,我们首先可以在忽略细节的前提下搞清楚管道处理HTTP请求的总体流程,然后再此基础上补充之前遗漏的细节.为了让读者朋友们能够更加容易地理解管道处理HTTP

学习ASP.NET Core, 怎能不了解请求处理管道[4]: 应用的入口——Startup

一个ASP.NET Core应用被启动之后就具有了针对请求的处理能力,而这个能力是由管道赋予的,所以应用的启动同时意味着管道的成功构建.由于管道是由注册的服务器和若干中间件构成的,所以应用启动过程中一个核心的工作就是完成中间节的注册.由于依赖注入在ASP.NET Core应用这得到非常广泛的应用,框架绝大部分的工作都会分配给我们预先注册的服务,所以服务注册也是启动WebHost过程的另一项核心工作.这两项在启动过程中必须完成的核心工作通过一个名为Startup的对象来承载. [本文已经同步到<A

ASP.NET Core管道深度剖析(3):管道是如何处理HTTP请求的?

我们知道ASP.NET Core请求处理管道由一个服务器和一组有序的中间件组成,所以从总体设计来讲是非常简单的,但是就具体的实现来说,由于其中涉及很多对象的交互,我想很少人能够地把它弄清楚.为了让读者朋友们能够更加容易地理解管道处理HTTP请求的总体流程,我们根据真实管道的实现原理再造了一个"模拟管道"并在此管道上开发了一个发布图片的应用,这篇文章旨在为你讲述管道是如何处理HTTP请求的 目录 一.HttpApplication     FeatureCollection     Ho

ASP.NET Core管道深度剖析(4):管道是如何建立起来的?

在<管道是如何处理HTTP请求的?>中,我们对ASP.NET Core的请求处理管道的构成以及它对请求的处理流程进行了详细介绍,接下来我们需要了解的是这样一个管道是如何被构建起来的.这样一个管道由一个服务器和一个HttpApplication构成,前者负责监听请求并将接收的请求传递给给HttpAppkication对象处理,后者则将请求处理任务委托给注册的中间件来完成.中间件的注册是通过ApplicationBuilder对象来完成的,所以我们先来了解一下这究竟是个怎样的对象. 目录 Appl

学习ASP.NET Core,怎能不了解请求处理管道[2]: 服务器在管道中的“龙头”地位

ASP.NET Core管道由注册的服务器和一系列中间件构成.我们在上一篇中深入剖析了中间件,现在我们来了解一下服务器.服务器是ASP .NET Core管道的第一个节点,它负责完整请求的监听和接收,最终对请求的响应同样也由它完成.[本文已经同步到<ASP.NET Core框架揭秘>之中] 服务器是我们对所有实现了IServer接口的所有类型以及对应对象的统称.如下面的代码片段所示,这个接口具有一个只读属性Features返回描述自身特性集合的FeatureCollection对象,另一个St

学习ASP.NET Core,怎能不了解请求处理管道[1]: 中间件究竟是个什么东西?

ASP.NET Core管道虽然在结构组成上显得非常简单,但是在具体实现上却涉及到太多的对象,所以我们在 "通过重建Hosting系统理解HTTP请求在ASP.NET Core管道中的处理流程"(上篇.中篇.下篇) 中围绕着一个经过极度简化的模拟管道讲述了真实管道构建的方式以及处理HTTP请求的流程.在本系列 中,我们会还原构建模拟管道时可以舍弃和改写的部分,向读者朋友们呈现一个真是的HTTP请求处理管道. ASP.NET Core 的请求处理管道由一个服务器与一组有序排列的中间件构成

学习ASP.NET Core, 怎能不了解请求处理管道[6]: 管道是如何随着WebHost的开启被构建出来的?

注册的服务器和中间件共同构成了ASP.NET Core用于处理请求的管道, 这样一个管道是在我们启动作为应用宿主的WebHost时构建出来的.要深刻了解这个管道是如何被构建出来的,我们就必须对WebHost和它的创建者WebHostBuilder这个重要的对象具有深刻的理解.[本文已经同步到<ASP.NET Core框架揭秘>之中] 目录 一.WebHost     WebHostOptions     构建管道的三个步骤 二.WebHostBuilder     WebHost的创建    

学习ASP.NET Core, 怎能不了解请求处理管道[3]: 自定义一个服务器感受一下管道是如何监听、接收和响应请求的

我们在<服务器在管道中的"龙头"地位>中对ASP.NET Core默认提供的具有跨平台能力的KestrelServer进行了介绍,为了让读者朋友们对管道中的服务器具有更加深刻的认识,接下来我们采用实例演示的形式创建一个自定义的服务器.这个自定义的服务器直接利用HttpListener来完成针对请求的监听.接收和响应,我们将其命名为HttpListenerServer.在正式介绍HttpListenerServer的设计和实现之前,我们先来显示一下如何将它应用到 一个具体的W

学习ASP.NET Core, 怎能不了解请求处理管道[5]: 中间件注册可以除了可以使用Startup之外,还可以选择StartupFilter

中间件的注册除了可以借助Startup对象(DelegateStartup或者ConventionBasedStartup)来完成之外,也可以利用另一个叫做StartupFilter的对象来实现.所谓的StartupFilter是对所有实现了IStartupFilter接口的类型及其对象的统称.IStartupFilter接口定义了如下一个唯一的方法Configure,该方法的参数next返回的Action<IApplicationBuilder>对象体现了后续StartupFilter和St