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.statusCode
res.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;