Node服务器 - koa框架

news/2025/2/19 8:36:14/

1 koa的基本使用

2 koa的参数解析

3 koa响应和错误

4 koa静态服务器

5 koa的源码解析

6 和express对比

koa的基本使用过程

const Koa = require('koa')// 创建app对象
const app = new Koa()// 注册中间件(middleware)
// koa的中间件有两个参数: ctx/next
app.use((ctx, next) => {console.log('匹配到koa的中间件')// 向客户端发送消息ctx.body = '哈哈哈哈哈'
})// 启动服务器
app.listen(6000, () => {console.log('koa服务器启动成功~')
})

koa中ctx参数的解析

ctx包含了请求对象和响应对象

注意区分ctx.req和ctx.request;

区分ctx.res和ctx.response.

还包括其他的属性,比如ctx.query和ctx.params等等。

next()和express的用法差不多

const Koa = require('koa')// 创建app
const app = new Koa()// 中间件
app.use((ctx, next) => {// 1.请求对象console.log(ctx.request) // 请求对象: Koa封装的请求对象console.log(ctx.req) // 请求对象: Node封装的请求对象// 2.响应对象console.log(ctx.response) // 响应对象: Koa封装的响应对象console.log(ctx.res) // 响应对象: Node封装的响应对象// 3.其他属性console.log(ctx.query)// console.log(ctx.params)next()
})app.use((ctx, next) => {console.log('second middleware~')
})// 启动服务器
app.listen(6000, () => {console.log('koa服务器启动成功~')
})

koa区分路径和方式

在koa里面没有像express里面的app.get()和app.post()这样子的写法,只有app.use()。

并且也没有像express里面的app.get("/home"(){})和app.post("/home"(){})这样子的写法,koa需要手动判断路径,ctx.path可以拿到客户端访问服务器时候的路径是什么。

通过ctx.method可以拿到客户端访问服务器时候采用的是什么方式。

这种情况多了是肯定不方便也很繁琐,解决办法是使用路由。看下面一节的代码。

const Koa = require('koa')// 创建app
const app = new Koa()// 中间件: path/method使用路由
app.use((ctx, next) => {if (ctx.path === '/users') {if (ctx.method === 'GET') {ctx.body = 'user data list'} else if (ctx.method === 'POST') {ctx.body = 'create user success~'}} else if (ctx.path === '/home') {ctx.body = 'home data list~'} else if (ctx.path === '/login') {ctx.body = '登录成功, 欢迎回来~'}
})// 启动服务器
app.listen(6000, () => {console.log('koa服务器启动成功~')
})

koa路由的使用方法

下载对应的koa的路由

npm install @koa/router

下面这段代码是没有封装路由的写法: 

const Koa = require('koa')const KoaRouter = require('@koa/router')// 创建服务器app
const app = new Koa()// 路由的使用
// // 1.创建路由对象 /users对应的是后续路由的主要路径,即localhost:6000/users
// const userRouter = new KoaRouter({ prefix: '/users' })// // 2.在路由中注册中间件: path/method
// userRouter.get('/', (ctx, next) => {
//   ctx.body = 'users list data~'
// })
// userRouter.get('/:id', (ctx, next) => {
//   const id = ctx.params.id
//   ctx.body = '获取某一个用户' + id
// })
// userRouter.post('/', (ctx, next) => {
//   ctx.body = '创建用户成功~'
// })
// userRouter.delete('/:id', (ctx, next) => {
//   const id = ctx.params.id
//   ctx.body = '删除某一个用户' + id
// })
// userRouter.patch('/:id', (ctx, next) => {
//   const id = ctx.params.id
//   ctx.body = '修改某一个用户' + id
// })// 3.让路由中的中间件生效
app.use(userRouter.routes())
// 这个是用来提示客户端除了上面有的请求方式,其他的都是没有封装的方法,不能使用
app.use(userRouter.allowedMethods())// 启动服务器
app.listen(6000, () => {console.log('koa服务器启动成功~')
})

 下面的写法是针对封装了路由的:

 userRouter的代码:

const KoaRouter = require('@koa/router')// 1.创建路由对象  /users对应的是后续路由的主要路径,即localhost:6000/users
const userRouter = new KoaRouter({ prefix: '/users' })// 2.在路由中注册中间件: path/method
userRouter.get('/', (ctx, next) => {ctx.body = 'users list data~'
})
userRouter.get('/:id', (ctx, next) => {const id = ctx.params.idctx.body = '获取某一个用户' + id
})
userRouter.post('/', (ctx, next) => {ctx.body = '创建用户成功~'
})
userRouter.delete('/:id', (ctx, next) => {const id = ctx.params.idctx.body = '删除某一个用户' + id
})module.exports = userRouter
const Koa = require('koa')
const userRouter = require('./router/userRouter')// 创建服务器app
const app = new Koa()// 3.让路由中的中间件生效
app.use(userRouter.routes())
app.use(userRouter.allowedMethods())// 启动服务器
app.listen(6000, () => {console.log('koa服务器启动成功~')
})

koa中参数解析方式

解析get的两种数据是内置就能解决的,但是队与post的json格式的数据还得下载第三方的库:

npm install koa-bodyparser

这个库能解析json和urlencoded的消息体数据,但是不能成立formdata的数据 ,这个时候用到另外一个第三方库:

解析formdata的路径的路由才有必要使用这个解析,所以解析的方式是写在对应路由的中间件中 

npm install @koa-multer multer

 userRouter.post('/formdata', formParser.any(), (ctx, next) => {
  console.log(ctx.request.body)
  ctx.body = '用户的formdata信息'
})

const Koa = require('koa')
const KoaRouter = require('@koa/router')
const bodyParser = require('koa-bodyparser')
const multer = require('@koa/multer')// 创建app对象
const app = new Koa()// 使用第三方中间件解析body数据
app.use(bodyParser())
const formParser = multer()// 注册路由对象 /users对应的是后续路由的主要路径,即localhost:6000/users
const userRouter = new KoaRouter({ prefix: '/users' })/*** 1.get: params方式, 例子:/:id* 2.get: query方式, 例子: ?name=why&age=18* 3.post: json方式, 例子: { "name": "why", "age": 18 }* 4.post: x-www-form-urlencoded* 5.post: form-data*/
// 1.get/params
userRouter.get('/:id', (ctx, next) => {const id = ctx.params.idctx.body = 'user list data~:' + id
})// 2.get/query
userRouter.get('/', (ctx, next) => {const query = ctx.queryconsole.log(query)ctx.body = '用户的query信息' + JSON.stringify(query)
})// 3.post/json(使用最多)
userRouter.post('/json', (ctx, next) => {// 注意事项: 不能从ctx.body中获取数据//第三方库解析的json内容就是放到ctx.request.body里面,//ctx.req.body在这里是underfineconsole.log(ctx.request.body, ctx.req.body)// ctx.body用于向客户端返回数据ctx.body = '用户的json信息'
})// 4.post/urlencoded
userRouter.post('/urlencoded', (ctx, next) => {
//这个第三方库解析的urlencoded内容就是放到ctx.request.body里面,console.log(ctx.request.body)ctx.body = '用户的urlencoded信息'
})app.use(userRouter.routes())
app.use(userRouter.allowedMethods())// 5.post/form-data
userRouter.post('/formdata', formParser.any(), (ctx, next) => {console.log(ctx.request.body)ctx.body = '用户的formdata信息'
})// 启动服务器
app.listen(6000, () => {console.log('koa服务器启动成功~')
})

koa中文件上传方式

const Koa = require('koa')
const KoaRouter = require('@koa/router')
const multer = require('@koa/multer')// 创建app对象
const app = new Koa()// const upload = multer({
//   dest: './uploads'
// })// 给上传文件解析到 ./uploads文件夹里面并且添加文件后缀
const upload = multer({storage: multer.diskStorage({destination(req, file, cb) {cb(null, './uploads')},filename(req, file, cb) {cb(null, Date.now() + "_" + file.originalname)}})
})// 注册路由对象 /upload对应的是后续路由的主要路径,即localhost:6000/uploads
const uploadRouter = new KoaRouter({ prefix: '/upload' })// 当文件的上传
uploadRouter.post('/avatar', upload.single('avatar'), (ctx, next) => {console.log(ctx.request.file)ctx.body = '文件上传成功~'
})//多文件上传
uploadRouter.post('/photos', upload.array('photos'), (ctx, next) => {console.log(ctx.request.files)ctx.body = '文件上传成功~'
})app.use(uploadRouter.routes())
app.use(uploadRouter.allowedMethods())// 启动服务器
app.listen(6000, () => {console.log('koa服务器启动成功~')
})

koa中部署静态资源

需要下载对应的第三方包:

npm install koa-static

使用之后可以给客户端提供图片地址,比如:http://localhost:8000/uploads/XXXX.jpg 

const Koa = require('koa')
const static = require('koa-static')const app = new Koa()// app.use((ctx, next) => {
//   ctx.body = "哈哈哈哈"
// })app.use(static('./uploads'))
app.use(static('./build'))app.listen(8000, () => {console.log('koa服务器启动成功~')
})

koa响应结果的方式

const fs = require('fs')
const Koa = require('koa')
const KoaRouter = require('@koa/router')// 创建app对象
const app = new Koa()// 注册路由对象
const userRouter = new KoaRouter({ prefix: '/users' })userRouter.get('/', (ctx, next) => {// 1.body的类型是string// ctx.body = 'user list data~'// 2.body的类型是Buffer// ctx.body = Buffer.from('你好啊, 李银河~')// 3.body的类型是Stream// const readStream = fs.createReadStream('./uploads/1668331072032_kobe02.png')// ctx.type = 'image/jpeg'// ctx.body = readStream// 4.body的类型是数据(array/object) => 使用最多ctx.status = 201ctx.body = {code: 0,data: [{ id: 111, name: 'iphone', price: 100 },{ id: 112, name: 'xiaomi', price: 990 },]}// 5.body的值是null, 自动设置http status code为204// ctx.body = null
})app.use(userRouter.routes())
app.use(userRouter.allowedMethods())// 启动服务器
app.listen(6000, () => {console.log('koa服务器启动成功~')
})

koa的错误处理方案

const Koa = require('koa')
const KoaRouter = require('@koa/router')// 创建app对象
const app = new Koa()// 注册路由对象
const userRouter = new KoaRouter({ prefix: '/users' })userRouter.get('/', (ctx, next) => {const isAuth = falseif (isAuth) {ctx.body = 'user list data~'} else {// ctx.body = {//   code: -1003,//   message: '未授权的token, 请检测你的token'// }// EventEmitterctx.app.emit('error', -1003, ctx)}
})app.use(userRouter.routes())
app.use(userRouter.allowedMethods())// 独立的文件: error-handle.js
app.on('error', (code, ctx) => {const errCode = codelet message = ''switch (errCode) {case -1001:message = '账号或者密码错误~'breakcase -1002:message = '请求参数不正确~'breakcase -1003:message = '未授权, 请检查你的token信息'break}const body = {code: errCode,message}ctx.body = body
})// 启动服务器
app.listen(6000, () => {console.log('koa服务器启动成功~')
})

koa和express对比

这里提前先说一点:在中间件中遇到next()就会马上跳到下一个中间件中执行中间件的内容;这个时候前一个中间件的next()后面如果还有一段代码的话就暂时先不执行了,等后续中间件没有next()了会以洋葱模型的方式回来继续执行每一个中间件的next()后面的一段代码。入下图显示的中间件。但是express 的异步情况不满足洋葱模型。

 

express中间件-执行同步

代码的执行顺序是

1、console.log('koa middleware01')   ctx.msg = 'aaa';2、aaa中的next()  ; 3、console.log('koa middleware02')  ctx.msg += 'bbb';4、bbb中的next()

4、console.log('koa middleware03')  ctx.msg += 'ccc'  ;  ;5、回到ccc看看有没有执行的代码;  6、回到aaa中的剩余代码ctx.body = ctx.msg ;。

最后向客户端发送的是aaabbbccc。

res.json(aaabbbccc)

const express = require('express')// 创建app对象
const app = express()// 编写中间件
app.use((req, res, next) => {console.log('express middleware01')req.msg = 'aaa'next()// 返回值结果res.json(req.msg)
})app.use((req, res, next) => {console.log('express middleware02')req.msg += 'bbb'next()
})app.use((req, res, next) => {console.log('express middleware03')req.msg += 'ccc'
})// 启动服务器
app.listen(9000, () => {console.log('express服务器启动成功~')
})

express中间件-执行异步

这里的执行顺序是1、console.log('koa middleware01')   ctx.msg = 'aaa';2、aaa中的next()  ; 3、console.log('koa middleware02')  ctx.msg += 'bbb';4、回到aaa中的剩余代码ctx.body = ctx.msg ;。

这里 res.json(req.msg)最后向客户端发送的是aaabbb

const express = require('express')
const axios = require('axios')// 创建app对象
const app = express()// 编写中间件
app.use((req, res, next) => {console.log('express middleware01')req.msg = 'aaa'next()// 返回值结果res.json(req.msg)
})app.use((req, res, next) => {console.log('express middleware02')req.msg += 'bbb'next()
})// 执行异步代码
app.use(async (req, res, next) => {console.log('express middleware03')const resData = await axios.get('http://123.207.32.32:8000/home/multidata')req.msg += resData.data.data.banner.list[0].title// 只能在这里返回结果})// 启动服务器
app.listen(9000, () => {console.log('express服务器启动成功~')
})

express像koa一样把所有中间件变成异步的也不能做到像koa一样执行顺序可以回到第一步。

下面代码的res.json(req.msg)结果还是aaabbb

​
const express = require('express')
const axios = require('axios')// 创建app对象
const app = express()// 编写中间件
app.use(async (req, res, next) => {console.log('express middleware01')req.msg = 'aaa'await next()// 返回值结果res.json(req.msg)
})app.use(async (req, res, next) => {console.log('express middleware02')req.msg += 'bbb'await next()
})// 执行异步代码
app.use(async (req, res, next) => {console.log('express middleware03')const resData = await axios.get('http://123.207.32.32:8000/home/multidata')req.msg += resData.data.data.banner.list[0].title// 只能在这里返回结果})// 启动服务器
app.listen(9000, () => {console.log('express服务器启动成功~')
})​

使用expree解决异步请求的办法就是在最后一个中间件res.json(req.msg)再输出客户端数据。顺序和同步一样

​
const express = require('express')
const axios = require('axios')// 创建app对象
const app = express()// 编写中间件
app.use(async (req, res, next) => {console.log('express middleware01')req.msg = 'aaa'await next()})app.use(async (req, res, next) => {console.log('express middleware02')req.msg += 'bbb'await next()
})// 执行异步代码
app.use(async (req, res, next) => {console.log('express middleware03')const resData = await axios.get('http://123.207.32.32:8000/home/multidata')req.msg += resData.data.data.banner.list[0].title// 只能在这里返回结果res.json(req.msg)
})// 启动服务器
app.listen(9000, () => {console.log('express服务器启动成功~')
})​

koa中间件-执行同步

这里执行的结果是ctx.body = aaabbbccc返回给客户端数据是aaabbbccc。

执行顺序是先执行

1、console.log('koa middleware01')   ctx.msg = 'aaa';2、aaa中的next()  ; 3、console.log('koa middleware02')  ctx.msg += 'bbb';4、bbb中的next()

4、console.log('koa middleware03')  ctx.msg += 'ccc'  ;  ;5、回到ccc看看有没有执行的代码;  6、回到aaa中的剩余代码ctx.body = ctx.msg ;。

这种执行顺序又叫洋葱模型。

const Koa = require('koa')
const KoaRouter = require('@koa/router')// 创建app对象
const app = new Koa()// 注册中间件
app.use((ctx, next) => {console.log('koa middleware01')ctx.msg = 'aaa'next()// 返回结果ctx.body = ctx.msg
})app.use((ctx, next) => {console.log('koa middleware02')ctx.msg += 'bbb'next()
})app.use((ctx, next) => {console.log('koa middleware03')ctx.msg += 'ccc'
})// 启动服务器
app.listen(6000, () => {console.log('koa服务器启动成功~')
})

koa中间件-执行异步

比如执行的中间件中有异步请求的代码,axios的请求。

下面这段代码有异步的中间件时,执行顺序是:1、console.log('koa middleware01')   ctx.msg = 'aaa';2、aaa中的next();3、console.log('koa middleware02')  ctx.msg += 'bbb'  ;4、 aaa中的剩余代码ctx.body = ctx.msg ; 。      这里 最后向客户端发送的是aaabbb

const Koa = require('koa')
const axios = require('axios')// 创建app对象
const app = new Koa()// 注册中间件
// 1.koa的中间件1
app.use( (ctx, next) => {console.log('koa middleware01')ctx.msg = 'aaa'next()// 返回结果ctx.body = ctx.msg
})// 2.koa的中间件2
app.use( (ctx, next) => {console.log('koa middleware02')ctx.msg += 'bbb'// 如果执行的下一个中间件是一个异步函数, 那么next默认不会等到中间件的结果, 就会执行下一步操作// 如果我们希望等待下一个异步函数的执行结果, 那么需要在next函数前面加awaitnext()console.log('----')
})// 3.koa的中间件3
app.use(async (ctx, next) => {console.log('koa middleware03')// 网络请求const res = await axios.get('http://123.207.32.32:8000/home/multidata')ctx.msg += res.data.data.banner.list[0].title
})// 启动服务器
app.listen(6000, () => {console.log('koa服务器启动成功~')
})

所以,如果想要使得有异步中间件的情况下还是能够像同步那样都执行完中间件之后在返回结果的办法就是全部中间件转成异步的。最后向客户端发送的是aaabbbXXXX,顺序和同步一样

const Koa = require('koa')
const axios = require('axios')// 创建app对象
const app = new Koa()// 注册中间件
// 1.koa的中间件1
app.use(async (ctx, next) => {console.log('koa middleware01')ctx.msg = 'aaa'await next()// 返回结果ctx.body = ctx.msg
})// 2.koa的中间件2
app.use(async (ctx, next) => {console.log('koa middleware02')ctx.msg += 'bbb'// 如果执行的下一个中间件是一个异步函数, 那么next默认不会等到中间件的结果, 就会执行下一步操作// 如果我们希望等待下一个异步函数的执行结果, 那么需要在next函数前面加awaitawait next()console.log('----')
})// 3.koa的中间件3
app.use(async (ctx, next) => {console.log('koa middleware03')// 网络请求const res = await axios.get('http://123.207.32.32:8000/home/multidata')ctx.msg += res.data.data.banner.list[0].title
})// 启动服务器
app.listen(6000, () => {console.log('koa服务器启动成功~')
})

 

 

 

 

 

 

 

 


http://www.ppmy.cn/news/264974.html

相关文章

使用TypeScript实现一个浏览器事件的集中管理

使用TypeScript实现一个浏览器事件的集中管理 1. 浏览器事件模型2. EventTarget接口3.使用TypeScript实现浏览器事件的集中管理 1. 浏览器事件模型 浏览器的事件模型是一种基于事件驱动的编程模型,用于处理用户与浏览器交互时触发的各种事件。它包括三个主要阶段&a…

【云原生网关】Apache ShenYu 使用详解

目录 一、前言 二、Apache ShenYu 介绍 2.1 为什么叫ShenYu 2.2 ShenYu特点 2.3 ShenYu架构图 2.4 shenyu数据同步原理 2.4.1 Zookeeper数据同步原理 三、Apache ShenYu 安装部署 3.1 部署流程 3.1.1 创建 Docker Network 3.1.2 拉取Apache ShenYu Admin镜像 3.1.3…

车机导航流程

整体架构 1 导航应用作为导航状态管理和导航数据管理,将状态和导航数据通过framework将数据发送给驱动 2 驱动通过SPI将数据发送到MCU,MCU转发给仪表 3 仪表解析数据对导航状态、导航数据进行显示 导航流程 1 在结束导航时一定要清除发送buffer&#x…

御用导航提示提醒_AR实景导航,让你安全驾驶,不再“绕弯”

虽然现在手机、车机的导航能力越来越强,但是当我们遇到不熟悉的路况,特别是在立交桥和高速匝道口时还是会出拐错弯或错过路口的情况,而 往往错过了一个出口,就意味着你要多跑 几公里甚至更远! ! 基于当前复…

GPS北斗定位模块对车辆导航的意义

如今是私家车横行的时代,多到每天都要面临堵车,如何在车流中快速行驶,需要一个智能的导航系统,提示驾驶员们哪条道路上行驶了多少车辆,来辅助安全驾驶,了解周边交通情况。 这样的一套导航系统背后包含了无…

计算机专业孙玉辉,面向自主驾驶的智能车辆导航平台技术研究

摘要: 智能交通系统(Intelligent Transport System,ITS)可以显著提高交通效率,增强车辆运行安全性,减少能源耗费与尾气排放,是现代交通运输系统的重要发展方向.智能车辆(Intelligent Vehicle,IV)是ITS的核心和主要组成部分,是实现ITS人—车—路一体化的关键技术,其研…

车rc陀螺仪测试软件,车辆运动测量-加速度计和陀螺仪的介绍

车辆运动测量-加速度计和陀螺仪的介绍 有运动加速度时,歪斜传感器将得到一个不精确的倾角。也就是说,在车辆歪斜时只经过加速度计将无法得到精确的倾角。经过丈量绕车辆重心的旋转,陀螺仪有助于纠正车俩向前歪斜带来的晦气影响。不幸的是&…

matlab 零速检测,一种基于车辆零速检测的惯性导航误差修正方法与流程

本发明涉及车载导航与定位领域,尤其是涉及一种基于车辆零速检测的惯性导航误差修正方法。 背景技术: 惯性导航系统(inertialnavigationsystem,ins)能根据惯性传感器(陀螺仪、加速度计)提供的载体相对于惯性空间的线速度和角速度信息,成为车载组合定位系统关键部件。惯性导航…