express & koa & egg

2,320 阅读4分钟

express

express是一个基于 Node.js 平台的极简、灵活的 web 应用开发框架,主要基于 Connect 中间件,并且自身封装了路由、视图处理等功能,

Express 提供了 4 个主要特性:

  1. 与纯 Node 中使用一个函数处理所有请求的代码不同, Express 则使用“中间件栈”处理流。
  2. 路由与中间件类似,只有当你通过特定 HTTP 方法访问特定 URL 时才会触发处理函数的调用。
  3. 对 request 和 response 对象方法进行了拓展。
  4. 视图模块允许你动态渲染和改变 HTML 内容,并且使用其他语言编写 HTML 。

中间件栈

function myFunMiddleware(request, response, next) {
  ...     
  next(); 
}

express内置中间件

express.json、express.urlencoed、express.static

第三方中间件:

morgan、cookie-parser、body-parser、compression、helmet、connect-ratelimit

路由

var express = require("express");
var path = require("path");
var http = require("http");
var app = express();

// 像之前一样设置静态文件中间件。
// 所有的请求通过这个中间件,如果没有文件被找到的话会继续前进
var publicPath = path.resolve(__dirname, "public");
app.use(express.static(publicPath));

// 当请求根目录的时候被调用
app.get("/", function(request, response) {
    response.end("Welcome to my homepage!");
});

// 当请求/about的时候被调用
app.get("/about", function(request, response) {
    response.end("Welcome to the about page!");
});

// 当请求/weather的时候被调用
app.get("/weather", function(request, response) {
    response.end("The current weather is NICE.");
});

// 前面都不匹配,则路由错误。返回 404 页面
app.use(function(request, response) {
    response.statusCode = 404;
    response.end("404");
});
http.createServer(app).listen(3000);

复杂路由

// 指定“hello”为路由的固定部分
app.get("/hello/:who", function(request, response) {
    // :who 并不是固定住,它表示 URL 中传递过来的名字
    response.end("Hello, " + request.params.who + ".");
   
});

扩展 request 和 response

req.ip,res.status,res.send...

response.redirect("/hello/world");
response.redirect("http://expressjs.com");

response.sendFile("path/to/cool_song.mp3")

// ip黑名单
var EVIL_IP = "123.45.67.89";
app.use(function(request, response, next) {
    if (request.ip === EVIL_IP) {
        response.status(401).send("Not allowed!");
    } else {
        next();
    }
});

视图

应对动态内容的渲染,社区中出现了大量的 Express 模版引擎,例如: EJS、Handlebars、Pug。

var express = require("express");
var path = require("path");
var app = express();

// 告诉 Express 你的视图存在于一个名为 views 的文件夹中
app.set("views", path.resolve(__dirname, "views"));

// 告诉 Express 你将使用EJS模板引擎
app.set("view engine", "ejs");

app.get("/", function(request, response) {
    response.render("index", {
        message: "Hey everyone! This is my webpage."
    });
});
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello, world!</title>
</head>
<body>
    <%= message %>
</body>
</html>

koa

Koa是一个设计非常精简的Web框架,是 Express 原班人马基于 ES7 新特性重新开发的框架。框架本身不含任何中间件,可以使我们根据自身需要去组合一些中间件使用。它结合async/await实现了洋葱模式。

路由

const Koa = require('koa')
const route = require('koa-route')

const app = new Koa()

app.use(route.get('/', async (ctx) => {
  ctx.body = 'Hello Koa'
}))

app.listen(3000)

视图

const Koa = require('koa')
const route = require('koa-route')
const views = require('koa-views')
const app = new Koa()

app.use(views(path.join(__dirname, './views'), {
  extension: 'pug'
}))

app.use(route.get('/', async (ctx) => {
  await ctx.render('index', {
    title: 'Koa'
  })
}))

koa vs express

异常处理

Express 使用 Node 约定的 "error-first 回调" 处理异常,并通过中间件传播。 Koa 通过同步方式编写异步代码,可以通过 try catch 处理异常,非常自然。

// Express
app.use(function (err, req, res, next) {
  res.status(err.status || 500).send('error')
}) 
// Koa
app.use(async (ctx, next) => {
  try {
    await next()
  } catch (err) {
    ctx.app.emit('error', err)
    ctx.status = err.status || 500
    ctx.body = { message: err.message }
  }
})

Context

Koa 新增了一个 Context 对象,用来代替 Express 中的 Request 和 Response,作为请求的上下文对象。 Context 上除了 Request 和 Response 两个对象之外,还有 Node.js 原生提供的 req 、res、socket 等对象。

中间件模型

express使用的connect中间件模型

const connect = require('connect')
const app = connect()

app.use(function m1 (req, res, next) {
  console.log('m1')
  next()
  console.log('m1 end')
})

app.use(function m2 (req, res, next) {
  console.log('m2')
  next()
  console.log('m2 end')
})

app.use(function m3 (req, res, next) {
  console.log('m3')
  res.end('hello')
})

app.listen(8080)

/*
m1
m2
m3
m2 end
m1 end
*/

connect的简化模型

http.createServer(function (req, res) {
  console.log('m1')
  m1 (req, res) {
    console.log('m2')
    m2 (req, res) {
      m3 (req, res) {
        console.log('m3')
        res.end('hello')
      }
    }
    console.log('m2 end')
  }
  console.log('m1 end')
})

koa的洋葱圈模型

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

app.use(async function m1 (ctx, next) {
  console.log('m1')
  await next()
  console.log('m1 end')
})

app.use(async function m2 (ctx, next) {
  console.log('m2')
  await next()
  console.log('m2 end')
})

app.use(async function m3 (ctx) {
  console.log('m3')
  ctx.body = 'hello'
})

app.listen(8080)

//输出与connect模型一致

koa简化模型

Promise.resolve(async m1 () {
  console.log(m1)
  await Promise.resolve(async m2 () {
    console.log(m2)
    await Promise.resolve(async m3 () {
      console.log(m3)
      ctx.body = 'xxx'
     })
     console.log(m2 end)
  })
  console.log(m1 end)
})

egg

egg.js是阿里旗下基于node.js和koa是一个node企业级应用开发框架,可以帮助开发团队,和开发人员减少成本。 基于koa2、es6、es7使得node具有更有规范的开发模式,更低的学习成本、更优雅的代码、更少的维护成本。