代码地址:https://github.com/changeclass/Node_Blog_koa2.git
# async 与 await
异步 promise 写法
getFileContent('a.json').then(aData => { | |
console.log('a data', aData) | |
return getFileContent(aData.next) | |
}).then(bData => { | |
console.log('b data', bData) | |
return getFileContent(bData.next) | |
}).then(cData => { | |
console.log('c data', cData) | |
}) |
async 与 await 写法
async function readFileData() { | |
// 同步写法 | |
try { | |
const aData = await getFileContent("a.json"); | |
console.log("a data", aData); | |
const bData = await getFileContent(aData.next); | |
console.log("b data", bData); | |
const cData = await getFileContent(bData.next); | |
console.log("c data", cData); | |
} catch (err) { | |
console.error(err); | |
} | |
} | |
readFileData(); |
await
后面可以追加promise
对象,获取resolve
的值await
必须包裹在async
函数里面async
函数执行返回的也是一个promise
对象try-catch
截获promise
中reject
的值
# koa2
安装 koa2
npm install koa-generator -g
初始化项目
koa2 blog-koa2
安装环境参数的插件
yarn add cross-env --dev
运行项目
yarn run dev
默认端口为 3000
# 路由
koa2 使用路由需要单独引用 koa-router
插件。其余与 express 类似。但是有几点需要注意:
- 中间件必须是
async
函数 - 中间件函数
- 第一个参数 ctx 表示 request 与 response 的集合体
- 第二个参数 next 与 express 一样
const router = require('koa-router')() | |
router.get('/', async (ctx, next) => { | |
await ctx.render('index', { | |
title: 'Hello Koa 2!' | |
}) | |
}) | |
router.get('/string', async (ctx, next) => { | |
ctx.body = 'koa2 string' | |
}) | |
router.get('/json', async (ctx, next) => { | |
ctx.body = { | |
title: 'koa2 json' | |
} | |
}) | |
module.exports = router |
如果使用前缀需要调用 prefix
方法。例如:
const router = require('koa-router')() | |
router.prefix('/users') | |
router.get('/', function (ctx, next) { | |
ctx.body = 'this is a users response!' | |
}) | |
router.get('/bar', function (ctx, next) { | |
ctx.body = 'this is a users/bar response' | |
}) | |
module.exports = router |
# 添加自己的路由
首先添加一个获取博客列表的路由。
在
routes
文件夹新建一个blog.js
文件const router = require("koa-router")();
// 定义前缀
router.prefix("/api/blog");
// 路由 /api/blog/list
router.get("/list", async function (ctx, next) {
const query = ctx.query;
ctx.body = {
errno: 0,
query,
data: ["博客列表"],
};
});
module.exports = router;
在
app.js
中引入文件const blog = require("./routes/blog");
在
app.js
中注册路由app.use(blog.routes(), blog.allowedMethods());
# 中间件机制
基本上与 express 中间件一样
// logger | |
app.use(async (ctx, next) => { | |
// 当前请求耗时 | |
const start = new Date(); | |
await next(); | |
const ms = new Date() - start; | |
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`); | |
}); |
# 实现 session
安装插件
yarn add koa-generic-session koa-redis redis
在
app.js
中引入这两个工具const session = require("koa-generic-session");
const redisStore = require("koa-redis");
在处理路由之前配置 session
//session 配置
app.keys = ["12323213sad"]; // 设置 session 加密密匙
app.use(
session({
cookie: {
path: "/",
httpOnly: true,
maxAge: 24 * 60 * 60 * 1000,
},
store: redisStore({
all: "127.0.0.1:6379", // 写死本地的 server
}),
})
);
测试
router.get("/session-test", async function (ctx, next) {
console.log(ctx.session);
if (ctx.session.viewCount == null) {
ctx.session.viewCount = 0;
}
ctx.session.viewCount++;
ctx.body = {
errno: 0,
viewCount: ctx.session.viewCount,
};
});
# 开发路由 - 准备工作
安装插件
yarn add mysql xss
复用 express 项目的代码
- controller 文件夹
- db 文件夹
- middleware 文件夹
- model 文件夹
- utils 文件夹
复用 express 的代码后需要将其改写成 async 与 await 的语法。例如 user 的 controller
const login = async (username, password) => {
username = escape(username);
// 加密密码
password = genPassword(password);
password = escape(password);
const sql = `select username,realname from users where username=${username} and password=${password};`;
const rows = await exec(sql);
return rows[0] || {};
};
中间件需要将 req 与 res 合并成 ctx
module.exports = async (ctx, next) => {
if (ctx.session.username) {
await next();
return;
}
ctx.body = new ErrorModel("未登陆");
};
# 开发路由 - 路由改写
大部分与 express 一致,只是写法需要使用 koa2 的写法。例如 user.js
// 路由 /api/user/login | |
router.post("/login", async function (ctx, next) { | |
const { username, password } = ctx.request.body; | |
const data = await login(username, password); | |
if (data.username) { | |
// 操作 Session | |
ctx.session.username = data.username; | |
ctx.session.realName = data.realName; | |
ctx.body = new SuccessModel("登陆成功"); | |
return; | |
} else { | |
ctx.body = new ErrorModel("登陆失败"); | |
} | |
}); |
# 日志
koa2 的日志也需要使用 morgan,但 koa2 没有自带 morgan,因此需要自己引入一个插件。
安装插件
yarn add koa-morgan
引入插件
const path = require("path");
const fs = require("fs");
const morgan = require("koa-morgan");
编写逻辑
// 日志记录的级别
const ENV = process.env.NODE_ENV; // 当前运行的环境
if (ENV !== "production") {
app.use(
// 开发环境 测试环境
morgan("dev", {
stream: process.stdout,
})
);
} else {
const logFileName = path.join(__dirname, "logs", "access.log");
const writeStream = fs.createWriteStream(logFileName, {
flags: "a",
});
app.use(
// 线上环境
morgan("combined", {
stream: writeStream,
})
);
}