Koa.js
Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造,致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。通过利用 async 函数,Koa 帮你丢弃回调函数,并有力地增强错误处理。
1. 基础使用
1.1 安装和设置
# 创建新项目
mkdir koa-app
cd koa-app
npm init -y
# 安装 Koa
npm install koa
# 安装常用中间件
npm install koa-router koa-bodyparser koa-logger koa-cors koa-helmet
1.2 基本应用
// app.js
const Koa = require('koa');
const app = new Koa();
const port = 3000;
// 中间件
app.use(async (ctx, next) => {
try {
await next();
} catch (err) {
ctx.status = err.status || 500;
ctx.body = { error: err.message };
ctx.app.emit('error', err, ctx);
}
});
// 路由
app.use(async ctx => {
ctx.body = 'Hello World';
});
// 错误处理
app.on('error', (err, ctx) => {
console.error('server error', err);
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
2. 路由系统
2.1 基础路由
// routes/users.js
const Router = require('koa-router');
const router = new Router({
prefix: '/users'
});
// GET /users
router.get('/', async (ctx) => {
ctx.body = [{ id: 1, name: 'John' }];
});
// GET /users/:id
router.get('/:id', async (ctx) => {
const { id } = ctx.params;
ctx.body = { id, name: 'John' };
});
// POST /users
router.post('/', async (ctx) => {
const user = ctx.request.body;
ctx.status = 201;
ctx.body = user;
});
module.exports = router;
// app.js
const usersRouter = require('./routes/users');
app.use(usersRouter.routes());
app.use(usersRouter.allowedMethods());
2.2 嵌套路由
const Router = require('koa-router');
const forums = new Router({
prefix: '/forums'
});
const posts = new Router({
prefix: '/:forumId/posts'
});
posts.get('/', async (ctx) => {
ctx.body = `Posts in forum ${ctx.params.forumId}`;
});
posts.post('/', async (ctx) => {
ctx.body = `Create post in forum ${ctx.params.forumId}`;
});
forums.use(posts.routes(), posts.allowedMethods());
app.use(forums.routes());
3. 中间件
3.1 常用中间件
const Koa = require('koa');
const bodyParser = require('koa-bodyparser');
const logger = require('koa-logger');
const cors = require('@koa/cors');
const helmet = require('koa-helmet');
const serve = require('koa-static');
const app = new Koa();
// 日志中间件
app.use(logger());
// 安全中间件
app.use(helmet());
// CORS 中间件
app.use(cors());
// Body 解析
app.use(bodyParser());
// 静态文件服务
app.use(serve('./public'));
// 自定义中间件
app.use(async (ctx, next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
ctx.set('X-Response-Time', `${ms}ms`);
});
3.2 错误处理中间件
// middleware/error.js
module.exports = async (ctx, next) => {
try {
await next();
} catch (err) {
ctx.status = err.status || 500;
ctx.body = {
error: {
message: err.message,
status: ctx.status,
stack: process.env.NODE_ENV === 'development' ? err.stack : undefined
}
};
ctx.app.emit('error', err, ctx);
}
};
// 自定义错误
class AppError extends Error {
constructor(message, status = 500) {
super(message);
this.status = status;
}
}
4. 数据库集成
4.1 MongoDB (Mongoose)
const mongoose = require('mongoose');
// 连接数据库
mongoose.connect('mongodb://localhost/koa-app', {
useNewUrlParser: true,
useUnifiedTopology: true
});
// 定义模型
const userSchema = new mongoose.Schema({
name: String,
email: { type: String, required: true, unique: true },
password: { type: String, required: true }
});
const User = mongoose.model('User', userSchema);
// 使用模型
router.post('/users', async (ctx) => {
try {
const user = new User(ctx.request.body);
await user.save();
ctx.status = 201;
ctx.body = user;
} catch (error) {
ctx.throw(400, error.message);
}
});
4.2 SQL (Sequelize)
const { Sequelize, DataTypes } = require('sequelize');
// 连接数据库
const sequelize = new Sequelize('database', 'username', 'password', {
host: 'localhost',
dialect: 'mysql'
});
// 定义模型
const User = sequelize.define('User', {
name: DataTypes.STRING,
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
password: {
type: DataTypes.STRING,
allowNull: false
}
});
// 使用模型
router.post('/users', async (ctx) => {
try {
const user = await User.create(ctx.request.body);
ctx.status = 201;
ctx.body = user;
} catch (error) {
ctx.throw(400, error.message);
}
});