起步
安装
$ npm init -y
$ npm install koa
第一个程序
新建 index.js
文件
const Koa = require('koa')
const app = new Koa()
app.use(async ctx => {
ctx.body = 'Hello World'
})
app.listen(3000)
启动
$ node index.js
开发环境可以使用 nodemon 来进行热更新
$ npm install nodemon -D
修改 package.json
文件,添加 "dev": "nodemon index.js"
{
"name": "koa-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
+ "dev": "nodemon index.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"koa": "^2.13.4"
},
"devDependencies": {
"nodemon": "^2.0.20"
}
}
此时使用 npm run dev
来运行我们的开发环境
路由
安装 koa-router
$ npm install @koa/router
修改 index.js
文件
const Koa = require('koa')
const app = new Koa()
const router = require('@koa/router')()
router.get('/test', ctx => {
ctx.body = 'test page'
})
app.use(router.routes()).use(router.allowedMethods())
app.listen(3000)
重新执行 node index.js
或者等待 nodemon
热加载完毕
访问 http://localhost:3000/test
,此时可以看到页面输出内容 test page
获取请求数据
获取GET请求数据
- query 形式传参,通过
ctx.request.query
获取参数(request可省略),形如?xxx=xxx&xxx=xxx
router.get('/test', ctx => {
const query = ctx.request.query
ctx.body = {
query
}
})
访问 http://localhost:3000/test?name=zs&age=22
,输出:
{
"query": {
"name": "zs",
"age": "22"
}
}
- params 形式传参,通过
ctx.request.params
获取参数(request可省略),形如/users/xxx
router.get('/users/:id', ctx => {
const params = ctx.request.params
ctx.body = {
params
}
})
访问 http://localhost:3000/users/1
,输出:
{
"params": {
"id": "1"
}
}
获取POST请求数据
使用 koa-body 中间件
安装
$ npm install koa-body
index.js
文件中
const Koa = require('koa')
const app = new Koa()
const router = require('@koa/router')()
+ const koaBody = require('koa-body')
+ app.use(koaBody())
router.post('/', ctx => {
const body = ctx.request.body
ctx.body = {
body
}
})
app.use(router.routes()).use(router.allowedMethods())
app.listen(3000)
使用 ctx.request.body
接收 post 传参
可以使用 postman 、apifox 等 api 调试工具进行测试,或者使用 jetbrains 开发工具的 .http 文件进行测试
此时返回响应
{
"body": {
"id": 999,
"value": "content"
}
}
静态资源
安装 koa-static
$ npm install koa-static
根目录新建 assets/index.css
文件,写入
#app {
background-color: #ccc;
}
index.js
文件中
const Koa = require('koa')
const app = new Koa()
const router = require('@koa/router')()
const koaBody = require('koa-body')
+ const koaStatic = require('koa-static')
+ const path = require('path')
app.use(koaBody())
+ app.use(koaStatic(path.resolve(__dirname, 'assets')))
router.get('/', ctx => {
ctx.body = '111'
})
app.use(router.routes()).use(router.allowedMethods())
app.listen(3000)
访问 http://localhost:3000/index.css
文件上传
const Koa = require('koa')
const app = new Koa()
const router = require('@koa/router')()
const {koaBody} = require('koa-body')
const koaStatic = require('koa-static')
const path = require('path')
app.use(koaBody())
+ app.use(koaStatic(path.resolve(__dirname, 'upload')))
router.post('/upload', koaBody({
multipart: true,
formidable: {
uploadDir: path.resolve(__dirname, 'upload'),
keepExtensions: true,
}
}), ctx => {
const {file} = ctx.request.files
ctx.body = {
url: `${ctx.origin}/${file.newFilename}`
}
})
app.use(router.routes()).use(router.allowedMethods())
app.listen(3000)
postman 测试
浏览器打开 http://localhost:3000/6a70c105d00700018d83b5203.jpg
即可访问图片
模板引擎
art-template
安装 art-template
$ npm install art-template koa-art-template
使用
新建 view/index.art
文件
<!doctype html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>{{ title }}</h1>
</body>
</html>
index.js
文件
const Koa = require('koa')
const app = new Koa()
const router = require('@koa/router')()
const render = require('koa-art-template')
render(app, {
root: path.join(__dirname, 'view'),
extname: '.art',
debug: process.env.NODE_ENV !== 'production'
})
router.get('/', ctx => {
ctx.render('index', {
title: 'hello art-template'
})
})
app.use(router.routes()).use(router.allowedMethods())
app.listen(3000)
更多语法参考 https://aui.github.io/art-template/zh-cn/docs/index.html
错误处理
使用 koa-onerror 对错误进行处理,返回 json
格式
安装
$ npm install koa-onerror
使用
const Koa = require('koa')
const app = new Koa()
const onerror = require('koa-onerror')
// 404 Not Found
app.use(async (ctx, next) => {
await next()
if (ctx.status === 404) {
ctx.throw(404)
}
})
// error handler
onerror(app, {
accepts() {
return 'json'
},
json(err, ctx) {
ctx.body = {
code: ctx.status || 500,
msg: err.message
}
}
})
使用 ctx.throw([status], [msg], [properties])
抛出异常,如:ctx.throw(401, 'id is required')
数据库
koa2 中常使用 orm 框架来操作数据库,其中最常见的两个框架为 mongoose 和 sequelize ,分别对应 MongoDB 数据库和 MySQL 数据库。此外,sequelize 还支持 MariaDB,SQLite 和 PostgreSQL 数据库
mongoose
安装
$ npm install mongoose
连接
const mongoose = require('mongoose')
mongoose.connect('mongodb://username:password@host/database', {
useNewUrlParser: true,
useUnifiedTopology: true
}).then(() => {
console.log('数据库连接成功')
}).catch(error => {
console.log(error)
console.log('数据库连接失败')
})
创建一个模型
const mongoose = require('mongoose')
const userSchema = new mongoose.Schema({
username: {
type: String,
required: true
},
password: {
type: String,
required: true
},
email: String,
avatar: String
})
const User = mongoose.model('User', userSchema)
增删改查
- 增
router.post('/users', async ctx => {
const { username, password } = ctx.request.body
const user = await User.create({ username, password })
ctx.body = {
user
}
})
请求
POST http://localhost:3000/users
Content-Type: application/json
{
"username": "admin",
"password": "123456"
}
响应
{
"user": {
"username": "admin",
"password": "123456",
"_id": "6352c002f55b91e7f9187c6f",
"__v": 0
}
}
- 改
router.put('/users', async ctx => {
const { id } = ctx.query
const { username, password } = ctx.request.body
const user = await User.findByIdAndUpdate(id, { username, password }, { new: true })
ctx.body = {
user
}
})
请求
PUT http://localhost:3000/users?id=6352c002f55b91e7f9187c6f
Content-Type: application/json
{
"username": "admin1",
"password": "123456789"
}
响应
{
"user": {
"_id": "6352c002f55b91e7f9187c6f",
"username": "admin1",
"password": "123456789",
"__v": 0
}
}
- 删
router.delete('/users', async ctx => {
const { id } = ctx.query
const { username, password } = ctx.request.body
const user = await User.findByIdAndDelete(id, { username, password }, { new: true })
ctx.body = {
user
}
})
请求
DELETE http://localhost:3000/users?id=6352c002f55b91e7f9187c6f
响应
{
"user": {
"_id": "6352c002f55b91e7f9187c6f",
"username": "admin1",
"password": "123456789",
"__v": 0
}
}
- 查
router.get('/users', async ctx => {
const {id} = ctx.query
if (!id) {
const users = await User.find()
ctx.body = {
users
}
} else {
const user = await User.findById(id)
ctx.body = {
user
}
}
})
请求1
GET http://localhost:3000/users
响应1
{
"users": [
{
"_id": "6352c35680bd9bce302ad3f2",
"username": "admin",
"password": "123456",
"__v": 0
}
]
}
请求2
GET http://localhost:3000/users?id=6352c35680bd9bce302ad3f2
响应2
{
"user": {
"_id": "6352c35680bd9bce302ad3f2",
"username": "admin",
"password": "123456",
"__v": 0
}
}
const Koa = require('koa')
const app = new Koa()
const router = require('@koa/router')()
const koaBody = require('koa-body')
const koaStatic = require('koa-static')
const path = require('path')
const render = require('koa-art-template')
const mongoose = require('mongoose')
mongoose.connect('mongodb+srv://root:yuan521jin@oyal.vysd5.mongodb.net/koa-demo?ssl=true&authSource=admin', {
useNewUrlParser: true,
useUnifiedTopology: true
}).then(() => {
console.log('数据库连接成功')
}).catch(error => {
console.log(error)
console.log('数据库连接失败')
})
app.use(koaBody())
app.use(koaStatic(path.resolve(__dirname, 'assets')))
app.use(koaStatic(path.resolve(__dirname, 'upload')))
render(app, {
root: path.join(__dirname, 'view'),
extname: '.art',
debug: process.env.NODE_ENV !== 'production'
})
const userSchema = new mongoose.Schema({
username: {
type: String,
required: true
},
password: {
type: String,
required: true
},
email: String,
avatar: String
})
const User = mongoose.model('User', userSchema)
router.get('/users', async ctx => {
const {id} = ctx.query
if (!id) {
const users = await User.find()
ctx.body = {
users
}
} else {
const user = await User.findById(id)
ctx.body = {
user
}
}
})
router.post('/users', async ctx => {
const { username, password } = ctx.request.body
const user = await User.create({ username, password })
ctx.body = {
user
}
})
router.put('/users', async ctx => {
const { id } = ctx.query
const { username, password } = ctx.request.body
const user = await User.findByIdAndUpdate(id, { username, password }, { new: true })
ctx.body = {
user
}
})
router.delete('/users', async ctx => {
const { id } = ctx.query
const user = await User.findByIdAndDelete(id)
ctx.body = {
user
}
})
router.post('/upload', koaBody({
multipart: true,
formidable: {
uploadDir: path.resolve(__dirname, 'upload'),
keepExtensions: true,
}
}), ctx => {
const { file } = ctx.request.files
console.log(file)
ctx.body = {
url: `${ctx.origin}/${file.newFilename}`
}
})
app.use(router.routes()).use(router.allowedMethods())
app.listen(3000)