目录
一、快速入门
二、中间件
链式调用
洋葱圈模型
异步处理
三、路由
koa-router
四、请求参数解析
处理URL参数
处理body参数
五、错误处理
原生的错误处理
使用中间件
一、快速入门
新建文件夹使用VSCode打开,终端运行npm init -y生成package.json配置文件。安装koa,npm i koa。编写服务程序:src/start.js
1.导入koa包 2.实例化app对象 3.编写中间件 4.启动服务,监听3000端口
// 1.导入koa
const Koa=require('koa')
// 2.实例化对象
const app=new Koa()
// 3.编写中间件
app.use((ctx)=>{// ctx:context http请求的上下文(ctx.request:http请求 + ctx.response:http响应)ctx.body='hello koa2'
})
// 4.启动服务,监听3000端口
app.listen(3000,()=>{console.log('server is running on http://localhost:3000');
})
运行 node src/start.js 成功后显示http://localhost:3000
安装nodemon:npm i nodemon -D,运行 nodemon src/start.js。改变代码自动重启。
二、中间件
在请求和响应中间的处理程序;将从请求到响应的业务拆开成多个功能独立的函数,就是中间件;对于处理请求来说,在响应发出之前,可以在请求和响应之间做一些操作,并且将这个处理结果传递给下一个函数继续处理(类似工厂流水线)。
const Koa=require('koa')
const app=new Koa()
// 中间件
//简写可以省略app,写成app.use().use().use()
//在app.use中只能接收一个参数作为函数
app.use((ctx,next)=>{console.log('头部');next()
})
app.use((ctx,next)=>{console.log('身体');next()
})
app.use((ctx)=>{console.log('尾部');ctx.body='组装完成'
})
app.listen(3000,()=>{console.log('server is running on http://localhost:3000');
})
链式调用
app.use(function) 将给定的中间件方法添加到此应用程序;app.use()返回this,因此可以链式表达
洋葱圈模型
const Koa=require('koa')
const app=new Koa()
app.use((ctx,next)=>{console.log('1');next()console.log('2');
}).use((ctx,next)=>{console.log('3');next()console.log('4');
}).use((ctx,next)=>{console.log('5');ctx.body='处理完成'
})
// 输出 1 3 5 4 2
app.listen(3000,()=>{console.log('server is running on http://localhost:3000');
})
异步处理
依靠async await语法;async声明异步函数,await后跟promise对象。加了async的函数返回值会变为一个Promise对象
const Koa=require('koa')
const app=new Koa()
app.use(async (ctx,next)=>{
//middleware1中构造一个message=aactx.message='aa'await next()
//返回最终数据ctx.body=ctx.message
}).use(async (ctx,next)=>{
//middleware2中同步追加bbctx.message+='bb'await next()
}).use(async (ctx)=>{
//middleware3中异步追加ccconst res=await Promise.resolve('cc')ctx.message+=res
})
// 输出 aabbcc
app.listen(3000,()=>{console.log('server is running on http://localhost:3000');
})
三、路由
路由就是建立URL和处理函数之间的对应关系,用于根据不同的methods和URL返回不同的内容。
例如:使用postman测试接口,http://localhost:3000/users、GET方法返回’这是用户页’。
const Koa=require('koa')
const app=new Koa()
app.use((ctx)=>{// 编写时也可以省略request和response,直接写ctx.url ctx.bodyif(ctx.request.url=='/'){ctx.response.body='这是主页'}else if(ctx.request.url=='/users'){if(ctx.request.method=='GET')ctx.response.body='这是用户页'else if(ctx.request.method=='POST')ctx.response.body='创建用户'elsectx.response.status=405}else{ctx.response.status=404}
})
app.listen(3000)
koa-router
安装 npm i koa-router。使用:1.在koa的基础上导入koa-router包 2.实例化router对象 3.使用router处理路由 4.注册中间件
// 1.导入koa
const Koa=require('koa')
// 2.实例化对象
const app=new Koa()
// 3.使用koa-router
const Router=require('koa-router')
const router=new Router()
router.get('/',(ctx)=>{ctx.body='这是主页'
})
router.get('/users',(ctx)=>{ctx.body='这是用户页'
})
router.post('/users',(ctx)=>{ctx.body='创建用户'
})
// 4.注册中间件
app.use(router.routes())
// 支持返回405和501的错误
app.use(router.allowedMethods())
// 5.启动服务,监听3000端口
app.listen(3000,()=>{console.log('server is running on http://localhost:3000');
})
优化:
将一个模块放在单独的文件中,分离出一个router路由层。
1.创建src/router/user.route.js
2.将上面有关路由部分的代码放入此文件并进行导出module.exports=router
3.并在原文件中导入
const userRoute=require('./router/user.route')
app.use(userRoute.routes()).use(userRoute.allowedMethods())
四、请求参数解析
后端需要解析请求的参数,作为数据库操作的条件。接口设计:
1.获取对应id的用户信息GET/user/:id
2.查询年龄18-20的用户信息 GET/users?start=18&end=20
3.解析注册信息保存至数据库 POST/users{name:’a’,age:22}
对于不同的http请求,需要使用不同的方式携带参数;get请求在URL中以键值对传递,post/put/patch/delete请求在请求体中传递。
处理URL参数
1.query:在GET请求中,如果以键值对的形式传参,可以通过query得到。
2.params:在GET请求中,有些参数可以通过路由传参,可以通过params得到。
// 1.导入koa
const Koa=require('koa')
// 2.实例化对象
const app=new Koa()
// 3.使用koa-router
const Router=require('koa-router')
// 统一前缀
const router=new Router({prefix:'/users'})
const db=[{id:1,name:'a',age:18},{id:2,name:'b',age:20},{id:3,name:'c',age:22},
]
// 获取对应年龄的用户信息
router.get('/',(ctx)=>{// 赋默认值,值为空时不会出错const {start=0,end=0}=ctx.query //ctx.request.queryconst res=db.filter((item)=>item.age>=start&&item.age<=end)res.length==0?ctx.throw(404):(ctx.body=res)
})
// 获取对应id的用户信息
router.get('/',(ctx)=>{const id=ctx.params.idconst res=db.filter((item)=>item.id==id)// 找不到id 抛出错误if(!res[0]) ctx.throw(404)ctx.body=res[0]
})
router.post('/',(ctx)=>{ctx.body='创建用户'
})
// 4.注册中间件
app.use(router.routes())
// 支持返回405和501的错误
app.use(router.allowedMethods())
// 5.启动服务,监听3000端口
app.listen(3000,()=>{console.log('server is running on http://localhost:3000');
})
处理body参数
安装koa-body或koa-bodyparser,npm i koa-body
// 1.导入koa
const Koa=require('koa')
// 引入类要实例化,此处是函数,所以不需要
const { koaBody } = require('koa-body');
// 2.实例化对象
const app=new Koa()
// 在所有中间件注册前注册KoaBody
app.use(koaBody())
// 3.使用koa-router
const Router=require('koa-router')
// 统一前缀
const router=new Router({prefix:'/users'})
const db=[{id:1,name:'a',age:18},{id:2,name:'b',age:20},{id:3,name:'c',age:22},
]
router.post('/',(ctx)=>{db.push(ctx.request.body)ctx.body=db
})
// 4.注册中间件
app.use(router.routes())
// 支持返回405和501的错误
app.use(router.allowedMethods())
// 5.启动服务,监听3000端口
app.listen(3000,()=>{console.log('server is running on http://localhost:3000');
})
五、错误处理
原生的错误处理
一般Koa中的错误分三类
1.404,当请求的资源找不到,或者没有通过ctx.body返回时,由koa自动返回。
2.手动抛出,通过ctx.throw手动抛出。
3.500,运行错误
Koa类是继承Node的Emitter类,因此可以通过emit提交一个错误,通过on进行统一错误处理。
// 1.导入koa
const Koa=require('koa')
// 引入类要实例化,此处是函数,所以不需要
const { koaBody } = require('koa-body');
// 2.实例化对象
const app=new Koa()
// 在所有中间件注册前注册KoaBody
app.use(koaBody())
// 3.使用koa-router
const Router=require('koa-router')
// 统一前缀
const router=new Router({prefix:'/users'})
router.get('/:id/article/:aid',(ctx)=>{console.log(ctx.params);if(false){ctx.body={id:1,title:'文章1',content:'文章1'}}else{return ctx.app.emit('error',{code:404,message:'Resource is not found'},ctx)}
})
// 4.注册中间件
app.use(router.routes())
// 支持返回405和501的错误
app.use(router.allowedMethods())
app.on('error',(err,ctx)=>{console.error(err)ctx.body=err
})
// 5.启动服务,监听3000端口
app.listen(3000,()=>{console.log('server is running on http://localhost:3000');
})
使用中间件
安装 npm i koa-json-error
基础用法
const Koa=require('koa')
const app=new Koa()
// 注册并使用
const error=require('koa-json-error')
app.use(error())
app.use((ctx)=>{ctx.body='a'
})
app.listen(3000)
高级用法
const Koa=require('koa')
const app=new Koa()
// 注册并使用
const error=require('koa-json-error')
app.use(error({format:(err)=>{return {code:err.status,message:err.message,result:err.stack}},// obj是format的对象,将format返回的三个值解构postFormat:(err,obj)=>{const {result,...rest}=obj// 生产环境只返回code和message,开发环境下将错误堆栈result也一并返回// 要实现功能,需安装npm i cross-env,配置package.json文件:// "scripts":{// "dev":"nodemon src/index.js"// "prod":"NODE_ENV=production node src/index.js"// }// 生产环境运行npm run prod 开发环境运行npm run devreturn process.env.NODE_ENV=='production'?rest:obj}
}))
app.use((ctx)=>{ctx.body='a'
})
app.listen(3000)
(视频:B站杰哥课堂)