• Node学习二十 —— 构建和使用HTTP中间件


    中间件

    简单介绍一下中间件,我从通俗易懂地讲讲什么是中间件这里面摘抄的。

    我国企业从20世纪80年代开始就逐渐进行信息化建设,由于方法和体系的不成熟,以及企业业务和市场需求的不断变化,—个企业可能同时运行着多个不同的业务系统,这些系统可能基于不同的操作系统、不同的数据库、异构的网络环境。现在的问题是,如何把这些信息系统结合成一个有机地协同工作的整体,真正实现企业跨平台、分布式应用。

    中间件便是解决之道,它用自己的复杂换取了企业应用的简单,接下来我们来了解一下什么是中间件?

    中间件的概念听起来高大上,但其实我们平时都在使用,例如MySQL就可以看作是具备中间件特性的一种技术,中间件技术必须遵循一定的规范和协议,例如 TCP/IP、UDP协议等等,无规矩不成方圆,只有遵守一定的协议才能去处理事情。MySQL 就遵循了 TCP/IP 协议,在我们平常的开发中使用不同的编程语言比如 Java、Go、Python 等来操作 MySQL 的前提也是要遵循 TCP/IP协议,根据此协议实现了不通语言的连接模块来达到通信的目的。由此说使用中间件需要解决的第一个问题就是互通性,也就是相互间可以通信。我们后续学习到其他中间件可能会看到更多其他的协议,比如 AMQP、HTTP 协议等等,为什么呢?因为 TCP/IP 协议是底层的操作系统协议,它并不能满足我们业务场景中的所有需求,所以在其基础上构建一个自己请求信息来实现一个新的协议,比如 AMQP 协议就在信息头中增加消息内容tag标签、队列名、交换机名、连接定制信息等等。

    此外,中间件的第二个关键点是平台,平台就是用不同语言开发的应用程序,它们通过遵循某种协议和规范就能和底层操作系统硬件打交道来实现跨平台的效果,这就是中间件。

    1. 中间件技术首先能屏蔽底层操作系统的复杂性,如上图左半部分所示,我们对数据进行增删改查并不需要与底层操作系统的硬盘等各种指令打交道,我们只需要知道MySQL怎么使用,与MySQL进行交互即可,不需要管它是怎么进行存储和互联互通的。但是中间件的开发者就必须了解各种协议以及底层如何与操作系统的各种硬件进行交互的。

    2. 第二,中间件技术可以屏蔽技术架构的复杂性,以前单体架构所有服务都集中在一起用一种语言进行开发,但如今分布式架构下每一个微服务都可以采用不同的语言不同的技术栈,使用中间件就可以将不通的服务来连接互通起来,将不同技术架构的服务串联起来,来达到一个更加稳健、缩短开发周期维护成本低目的。

    中间件屏蔽了底层操作系统的复杂性,使程序开发人员面对一个简单而统一的开发环境,减少程序设计的复杂性,将注意力集中在自己的业务上,不必再为程序在不同系统软件上的移至而重复工作,从而大大减少了技术上的负担。中间件带给系统的,不只是开发的便捷,开发周期的缩短,也减少了系统的维护、运行和管理的工作量,还减少了计算机总体费用的投入。

    在WEB应用中,你可能需要检查请求,同时需要检查和修改响应,在Django、Cake等等典型HTTP框架中,执行这些操作的组件通常被称为中间件。这些中间件组件对请求-响应循环进行包装,在达到应用程序代码之前扩展请求对象或者在响应前后对其进行修改。

    一、Connect HTTP中间件框架

    一般而言,可以将中间件以堆栈的方式组织到一起,当Connect接收到HTTP请求时,就会按顺序调用每一个中间件。

    二、构建中间件

    中间件组件只是一个接收请求和响应的函数。

    const connect = require('connect');
    
    function hello(req,res){
        res.end("hello");
    }
    
    const app = connect.createServer(hello);
    
    app.listen(1234);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    创建了一个Connect服务器,并用hello中间件组件进行了初始化。

    2.1 创建异步组件

    中间件是可以异步的,当工作结束时,需要调用一个回调。前面的例子没有用到这个特性是因为结束了响应。

    function head(name,value) {
        return function(req,res,next){
            res.setHeader(name,value);
            next();
        }
    }
    
    const app = connect.createServer(
    	head('X-Powered-By', 'Node'),
        hello();
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2.3 错误处理

    如果没有中间件被设置来处理错误,那么就会以明文的形式显示错误结果。错误处理程序带有四个参数:错误、请求、响应、next。

    function errHandle(){
        return function(err, req, res, next){
            ...
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    最后可以将这个中间件放在最后一个顺序执行:

    const app = connect.createServer(
    	func1,
        func2,
        ...
        funcn,
        errHandle
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    三、HTTP中间件

    Connect不仅可以创建和使用HTTP中间件,它同时自己就自带一些中间件组件。

    3.1 记录请求

    const app = connect();
    
    app.use(connect.logger());
    
    app.use(function(req, res){
        res.end("hello");
    })
    
    app.listen(1234);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    上面使用了一种不同的语法来创建服务器,并且通过use来讲中间件添加进入中间件堆栈。这种方法和之前那种一样。

    使用这个中间件,那么就会看到服务器输出请求和响应的一些细节,并且可以通过给logger传递不同的参数设置输出,详情可以看官网。

    3.2 错误处理

    使用这个中间件,如果客户端接收text/html类型的内容,那么就会输出这个类型,如果是接收application/json类型的,就会输出这种类型,如果类型客户端都不接收,那么就会直接以明文输出。

    app.use(connect.errHandle());
    
    • 1

    如果用浏览器触发,那么刷新之后可以看到一个显示错误信息的页面。

    3.3 提交静态文件

    提供静态文件。

    // 设置静态服务器
    app.use(connect.static(__dirname + '/public'));
    
    • 1
    • 2

    在这个程序中,静态文件服务器会在public目录下查找文件,如果找到一个文件,文件就被提交,中间件链也会被中断,例如,在public 下放置一张图片,那么访问就会看到这个图片,如果访问的不是public文件夹,那么就会越过这个中间件继续执行下面的中间件。

    3.4 解析查询字符串

    URL后面可以跟参数,可以使用 query 中间件解析

    app.use(connect.query());
    
    • 1

    设置这个中间件之后,就可以在之后使用res.query获得一个对象,对象中是已经被解析好的路径传参。

    3.5 解析请求主体

    当提交表单的时候,有两种类型的请求主体编码格式:URL编码和多部件编码。URL编码格式和查询字符串格式类似,多部件编码是一种更为复杂的格式,主要用来上传文件以及传递更为复杂的数据类型。

    Connect附带一个通用的请求主体解析中间件,在请求对象上提供一个不可更改的body属性,该属性可在稍后被请求用到。

    app.use(connect.bodyParser);
    
    // 使用
    req.body
    
    • 1
    • 2
    • 3
    • 4

    3.6 解析Cookies

    Cookies是WEB浏览器上将数据存储为一个短字符串的一个标准,服务器可以发送一个或多个cookie,每一个cookie都有一个名称。服务器使用Set-Cookie响应头在任意请求类型的响应中发送一个或者多个cookie,浏览器必须存储每一个cookie,并将每一个作为后续请求上的单个Cookie头进行发送,直到过期为止。

    app.use(connect.cookieParser());
    
    // 使用
    req.cookies
    
    • 1
    • 2
    • 3
    • 4

    3.7 使用会话

    可以在服务器端保持会话,为将来的请求所用。当客户端首次 连接的时候,就创建了一个会话标识,并且Connect会发送包含会话标识符的浏览器cookie来关联浏览器和创建的会话。在以后的请求中,浏览器发送此cookie,改cookie允许服务器标识会话,并获取存储的会话对象以备进一步使用和修改。

    在服务器端,会话就是一个允许存储名词-值对的对象。默认下,Connect将会话存储在内存中,但是还可以修改让数据库等存储作为会话存储器。

    入股哦使用内存存储,那么会话无法在进程重启之后还存在。如果使用持久性存储器,将得到一个外部服务,会话在这个外部存储器中得到保持,并且能够在Node进程重启之后继续存在。

    app.use(connect.session({
        cookies: {
            // 多久会过期
            maxAge: 24 * 60 * 60 * 1000
        }
    }))
    
    // 可以这样拿到
    req.session
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3.8 其他可用中间件

    除了上面这些基础中间件,还有很多实用中间件:跨站请求伪造保护、Gzip压缩、静态文件缓存等等。

    可以使用Redis或者Memcache作为会话存储器,同时还可以使用MongoDB等等数据库作为会话存储器。

    很多第三方插件都和Conncet兼容,允许提供JSONP支持、显示模板、支持请求超时、整合不同的认证方法等等。

  • 相关阅读:
    嵌入式Linux应用开发-基础知识-第十九章驱动程序基石④
    redis cook book.notes.
    美团资深技术专家亲笔的400页的高并发系统设计,秒杀一众面试官
    黑群辉+腾讯云+frp内网穿透
    android源码-ContentProvider实现原理分析
    【笔试题】【day7】
    【C语言练习——打印空心下三角及其变形】
    想要精通算法和SQL的成长之路 - 环形子数组的最大和
    紫光展锐发布全新6G白皮书,展望泛在融合发展蓝图
    数据结构——【堆】
  • 原文地址:https://blog.csdn.net/qq_51574759/article/details/127125301