Express Koa 简述

2019-04-23  本文已影响0人  Perity

前言

在Express诞生前,没有成熟轮子,需要通过Nodejs基础模块构建应用

const http = require("http");
http.createServer(function(request, response){
  response.writeHead(200, {"Content-Type": "text/plain"});
  response.write("Hello world");
  response.end();
}).listen(8081);

Express

基于 Node.js 平台,快速、开放、极简的 Web 开发框架,这来自Express官方描述。

const express = require('express')
const app = express()

app.get('/', (req, res) => res.send('Hello World!'))

app.listen(3001, () => {
    console.info(`Server has started, 地址为: http://0.0.0.0:3001`)
})

Express是一个自身功能极简,完全是路由和中间件构成一个web开发框架:从本质上来说,一个Express应用就是在调用各种中间件。

可以看出中间件在Express开发中的重要性,这里主要就介绍一下中间件。

image.png

1、内置中间件

express.static 是Express目前唯一内置的一个中间件。用来处理静态资源文件。
例如,通过如下代码就可以将 public 目录下的图片、CSS 文件、JavaScript 文件对外开放访问了:
app.use(express.static('public'))
现在,你就可以访问 public 目录中的所有文件了:

http://localhost:3001/images/kitten.jpg
http://localhost:3001/css/style.css
http://localhost:3001/js/app.js
http://localhost:3001/images/bg.png
http://localhost:3001/hello.html

2、自定义中间件
这是一个名为“myLogger”的中间件函数的简单示例。当对应用程序的请求通过时,此函数只打印“LOGGED”。中间件函数被分配给名为的变量myLogger。

var express = require('express')
var app = express()

var myLogger = function (req, res, next) {
  console.log('LOGGED')
  next()
}

app.use(myLogger)

app.get('/', function (req, res) {
  res.send('Hello World!')
})

app.listen(3000)

每次应用程序收到请求时,它都会向终端输出消息“LOGGED”。

中间件加载的顺序很重要:首先加载的中间件函数也会先执行。

如果myLogger在到根路径的路由之后加载,则请求永远不会到达它并且应用程序不会打印“LOGGED”,因为根路径的路由处理程序终止请求 - 响应循环。

中间件函数myLogger只是打印一条消息,然后通过调用该next()函数将请求传递给堆栈中的下一个中间件函数。

Koa

Koa 是由 Express 原班人马打造的,致力于成为一个更小、更富有表现力、更健壮的 Web 框架。使用 Koa 编写 web 应用,通过组合不同的 generator,可以免除重复繁琐的回调函数嵌套,并极大地提升错误处理的效率。Koa 不在内核方法中绑定任何中间件,它仅仅提供了一个轻量优雅的函数库,使得编写 Web 应用变得得心应手。

// 导入koa,和koa 1.x不同,在koa2中,我们导入的是一个class,因此用大写的Koa表示:
const Koa = require('koa');

// 创建一个Koa对象表示web app本身:
const app = new Koa();

// 对于任何请求,app将调用该异步函数处理请求:
// 参数ctx是由koa传入的封装了request和response的变量,我们可以通过它访问request和response,next是koa传入的将要处理的下一个异步函数。
// 这里首先用await next();处理下一个异步函数,然后,设置的返回内容。
app.use(async (ctx, next) => {
    await next();
    ctx.body = 'Hello World';
});

// 在端口3001监听:
app.listen(3001);

console.info(`Server has started, 地址为: http://0.0.0.0:3001`)

Koa middleware

首先我们看一下执行的核心代码

app.use(async (ctx, next) => {
    await next();
    ctx.body = 'Hello World';
});

每收到一个http请求,Koa就会调用通过app.use()注册的async函数,并传入ctx和next参数。

我们可以对ctx操作,并设置返回内容。但是为什么要调用await next()?

因为Koa 中间件以更传统的方式级联,使用 async 功能,我们可以实现 “真实” 的中间件。通过一系列功能直接传递控制,直到一个返回,Koa 调用“下游”,然后控制流回“上游”。

下面以 “Hello World” 的响应作为示例,当请求开始时首先请求流通过 x-response-time 和 logging 中间件,然后继续移交控制给 response 中间件。当一个中间件调用 next() 则该函数暂停并将控制传递给定义的下一个中间件。当在下游没有更多的中间件执行后,堆栈将展开并且每个中间件恢复执行其上游行为。

const Koa = require('koa');
const app = new Koa();

// logger

app.use(async (ctx, next) => {
    await next(); // 调用下一个middleware
    const rt = ctx.response.get('X-Response-Time');
    console.log(`${ctx.method} ${ctx.url} - ${rt}`); // 打印日志
});

// x-response-time

app.use(async (ctx, next) => {
    const start = Date.now(); // 当前时间
    await next(); // 调用下一个middleware
    const ms = Date.now() - start; // 耗时时间
    ctx.set('X-Response-Time', `${ms}ms`); // 打印耗时时间
});

// response

app.use(async ctx => {
    ctx.body = 'Hello World';
});

app.listen(3001);

middleware的顺序很重要,也就是调用app.use()的顺序决定了middleware的顺序。

此外,如果一个middleware没有调用await next(),会怎么办?答案是后续的middleware将不再执行了。这种情况也很常见,例如,一个检测用户权限的middleware可以决定是否继续处理请求,还是直接返回403错误:

app.use(async (ctx, next) => {
    if (await checkUserPermission(ctx)) {
        await next();
    } else {
        ctx.response.status = 403;
    }
});

总结

Express基于ES5语法,通过回调组合逻辑。在复杂逻辑中会包含大量回调嵌套,难以捕捉问题,不便调试。当下Es6,Es7盛行,可以通过相关三方库完善支持Promise或Async/Await来弥补。

如果你喜欢diy,可以考虑koa,它有足够的扩展和中间件,而且自己写很简单
如果你想简单点,找一个框架啥都有,那么先使用express

浏览器向服务器发送一个请求后,服务器直接通过request.定位属性的方式得到通过request携带过去的数据(有用户输入的数据和浏览器本身的数据信息)。这中间就一定有一个函数将这些数据分类做了处理,已经处理好了,最后让request对象调用使用。对的,这个处理数据处理函数就是我们要说的 中间件 。

1、封装了一些处理一个完整事件的功能函数。

2、封装了一些或许复杂但肯定是通用的功能。

参考:

上一篇下一篇

猜你喜欢

热点阅读