Express Koa 简述

前言

  • Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。
    这也就让我们可以脱离浏览器运行JavaScript代码。

  • 在Node.js渐渐成熟走向商业化应用的过程中,必须要提起Express,Koa框架,它们均来自同一作者TJ--node圈中的人物,诞生于Nodejs发展的不同时期,在Ecmascript语言规范的发展中前行。

在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;
    }
});

总结

  • koa是一个比express更精简,使用node新特性的中间件框架,相比之前express就是一个庞大的框架。

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

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

  • 中间件理解

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

  • 中间件可以总结为以下两点:

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

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

参考:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容