Koa2 搭建 Node.js 项目
Koa 是 Express 团队打造的新 web server 框架,与 Express 的区别在于:
- Koa 不涉及路由及其他中间件的捆绑,体积比 Express 小;
- Koa 支持 async / await 写法,在异步处理上比 Express 的 Promise 回调写法更友好;
- Koa 使用洋葱圈模型的函数调用栈执行中间件,先调用的后执行完,而 Express 使用先进先出的任务队列执行中间件,先调用的先执行完。
一、Koa 项目搭建
1、全局安装脚手架
npm i koa-generator -g
2、新建 Koa 项目
# 新建 Koa 项目
koa2 new-project
# 装包和启动
npm i & npm start
3、项目启动优化
Koa 项目自带 nodemon 和 dev 等启动命令,不需要额外安装 nodemon 监测文件变化,自动重启 node。
与前面手动搭建 Node.js 项目同理,可以安装 cross-env 跨平台运行脚本,设置环境变量,兼容 mac、linux 和 windows;
npm i cross-env --save-dev
接着在 package.json 中修改:
{
"scripts": {
"dev": "./node_modules/.bin/nodemon bin/www",
"dev": "cross-env NODE_ENV=dev ./node_modules/.bin/nodemon bin/www",
"prd": "pm2 start bin/www",
"prd": "cross-env NODE_ENV=production pm2 start bin/www",
},
}
然后通过 npm run dev 启动项目即可。
二、Context 对象
Koa Context 将 node 的 request 和 response 对象封装到单个对象中,为编写 Web 应用程序和 API 提供了许多有用的方法。每个请求都将创建一个 Context:
app.use(async ctx => {
ctx; // 这是 Context
ctx.request; // 这是 koa Request
ctx.response; // 这是 koa Response
});
常用 API 如下:
ctx.req:Node 的request对象;ctx.res:Node 的response对象;注意绕过 Koa 的 response 处理是不被支持的,应避免使用以下 node 属性:res.statusCoderes.writeHead()res.write()res.end()
ctx.request:koa 的Request对象;ctx.response:koa 的Response对象;ctx.app:应用程序实例引用;ctx.cookies.get(name, [options]):通过options获取 cookiename;ctx.cookies.set(name, value, [options]):通过options设置 cookiename的value,可选属性如下:maxAge:number, 表示从Date.now()得到的毫秒数;expires:Date 对象, 表示 cookie 的到期日期 (默认在会话结束时过期)path:string, 表示 cookie 的路径 (默认为/)domain:string, 指示 cookie 的域 (无默认值)secure:boolean, 表示 cookie 是否仅通过 HTTPS 发送 (HTTP 下默认为false, HTTPS 下默认为true)httpOnly:boolean, 表示 cookie 是否仅通过 HTTP(S) 发送,, 且不提供给客户端 JavaScript (默认为true)sameSite:boolean | string, 表示该 cookie 是否为 "相同站点" cookie (默认为false). 可以设置为'strict','lax','none', 或true(映射为'strict')signed:boolean, 表示是否要对 cookie 进行签名 (默认为false)overwrite:boolean, 表示是否覆盖以前设置的同名的 cookie (默认是false)
ctx.throw([status], [msg], [properties]):抛出一个包含.status属性错误的帮助方法,其默认值为500。点击查看详情
1、Request 对象
ctx.header:请求头对象;ctx.headers:设置请求头对象;ctx.method:请求方法;ctx.method=:设置请求方法;ctx.url:获取请求 URL;ctx.url=:设置请求 URL;ctx.originalUrl:获取请求原始 URL;ctx.origin:获取 URL 的来源,包括protocol和host;ctx.href:获取完整的请求 URL,包括protocol,host和url;ctx.path:获取请求路径名;ctx.path=:设置请求路径名;ctx.query:获取解析的查询字符串, 当没有查询字符串时,返回一个空对象;ctx.query=:将查询字符串设置为给定对象;ctx.querystring:根据?获取原始查询字符串;ctx.querystring=:设置原始查询字符串;ctx.host:存在时获取主机(hostname:port);ctx.hostname:存在时获取主机名;ctx.fresh:检查请求缓存是否新鲜,即内容没有改变;ctx.stale:与request.fresh相反;ctx.socket:返回请求套接字;ctx.protocol:返回请求协议,https 或 http;ctx.secure:通过ctx.protocol == "https"来检查请求是否通过 TLS 发出;ctx.ip:请求远程地址;ctx.ips:当X-Forwarded-For存在且app.proxy被启用时,这些 ips 的数组被返回,从上游到下游排序,禁用时返回一个空数组;ctx.subdomains:以数组形式返回子域;ctx.is():检查传入请求是否包含Content-Type消息头字段,并且包含任意的 mimetype;ctx.accepts():检查给定的type(s)是否可以接受;ctx.acceptsEncodings():检查encodings是否可以接受;ctx.acceptsCharsets():检查charsets是否可以接受;ctx.acceptsLanguages():检查langs是否可以接受;ctx.get(field):返回具体请求头,field不区分大小写。
2、Response 对象
ctx.body:获取响应体;ctx.body=:设置响应体;ctx.status:获取响应状态;ctx.status=:通过数字代码设置响应状态;ctx.message:获取响应的状态消息;ctx.message=:将响应的状态消息设置为给定值;ctx.length=:将响应的 Content-Length 设置为给定值;ctx.length:以数字返回响应的 Content-Length,或者从ctx.body推导出来,或者undefined;ctx.type=:设置响应Content-Type通过 mime 字符串或文件扩展名;ctx.type:获取响应Content-Type, 不含 "charset" 等参数;ctx.headerSent:检查是否已发送响应标头;ctx.redirect(url):执行 302 重定向到url;ctx.attachment([filename], [options]):将Content-Disposition设置为 “附件” 以指示客户端提示下载;ctx.set(field, value):设置响应头field到value;ctx.append(field, val):用值val附加额外的消息头field;ctx.remove(field):删除消息头field;ctx.lastModified=:将Last-Modified消息头设置为适当的 UTC 字符串;ctx.etag=:设置包含"包裹的 ETag 响应。
三、Koa 框架下开发接口
- app.js
- routes/blog.js
app.js
// ...
const blog = require('./routes/blog')
// ...
app.use(blog.routes(), blog.allowedMethods())
// ...
routes/blog.js
const router = require('koa-router')()
router.get('/count', function (ctx, next) {
ctx.body = {
errno: 0,
data: 123
}
})
router.post('/list', function (ctx, next) {
const { page_num, page_size } = ctx.request.body
res.json({
errno: 0,
data: [...]
})
});
module.exports = router;
四、配置与连接 MySQL 数据库
配置和连接完,接下来进行接口对接开发:
- Koa 写法
- Express 写法
routes/blog.js
const router = require('koa-router')()
const {
getTotal,
getList,
getDetail
} = require('../controller/blog')
const { SuccessModel, ErrorModel } = require('../model/resModel')
router.prefix('/api/blog')
// 获取博客列表总数
router.get('/count', async function (ctx, next) {
const result = await getTotal()
ctx.body = new SuccessModel(result)
})
// 获取博客列表
router.post('/list', async (ctx, next) => {
const { page_num, page_size } = ctx.request.body
const result = await getList(page_num, page_size)
ctx.body = new SuccessModel(result)
});
// 获取博客详情
router.post('/detail', async (ctx, next) => {
const { id } = ctx.request.body
const result = await getDetail(id)
ctx.body = new SuccessModel(result)
});
module.exports = router
routes/blog.js
const express = require('express');
const router = express.Router();
const {
getTotal,
getList,
getDetail,
newBlog,
updateBlog,
delBlog
} = require('../controller/blog')
const {
SuccessModel,
ErrorModel
} = require('../model/resModel')
// 获取博客列表总数
router.get('/count', (req, res, next) => {
const result = getTotal()
return result.then(count => {
res.json(new SuccessModel(count))
})
});
// 获取博客列表
router.post('/list', (req, res, next) => {
const { page_num, page_size } = req.body
const result = getList(page_num, page_size)
return result.then(listData => {
res.json(new SuccessModel(listData))
})
});
// 获取博客详情
router.post('/detail', (req, res, next) => {
const { id } = req.body
const result = getDetail(id)
return result.then(data => {
res.json(new SuccessModel(data))
})
});
module.exports = router;