深入浅出koa框架

写在前面


大家好,我是一溪风月🌸,一名前端程序员,上篇文章我们学习了Express框架,这篇文章我们将学习和讲解Koa框架,事实上,Koa是Express同一个团队开发的一个新的Web框架,目前团队的核心开发者TJ的主要精力也在维护Koa,express已经交给团队维护了,Koa旨在为Web应用程序和API提供更小,更丰富和更强大的能力,相对于Express具有更强的异步处理能力,Koa的核心代码只有1600+行,是一个更加轻量的框架,我们可以根据需要安装和使用中间件,好了,让我们开始吧!

一.Koa初体验


首先我们像使用Express一样,来体验一下koa的Web服务器,Koa也是通过注册中间件来完成请求操作的,Koa注册的中间件提供了两个参数,参数分别如下:

ctx:上下文(Context)对象;

  • koa并没有像express一样,将req和res分开,而是将它们作为ctx的属性。
  • ctx代表一次请求的上下文对象。
  • ctx.request:获取请求的对象。
  • ctx.response:获取响应对象。

next:本质上是一个dispatch,类似于之前的next;

js 复制代码
const Koa = require("koa")

// 创建app对象
const app = new Koa()

// 注册中间件(middleware)
// koa的中间件有两个参数:ctx/next
app.use((ctx, next) => {
  // 1.请求对象
  console.log(ctx.request) // 请求对象:Koa封装的请求对象
  console.log(ctx.req) // 请求对象:Node封装的请求对象

  // 2.响应对象
  console.log(ctx.response)
  console.log(ctx.res)

  // 3.其他属性
  console.log(ctx.query)
})

app.listen(6000, () => {
  console.log("服务启动在6000端口🚀")
})

二.Koa中间件


我们使用Koa创建的应用,注册中间件只能通过use方法,因为Koa并没有提供methods的方式来注册中间件,也没有提供path中间件来匹配路径,但是真实开发中我们需要将路径和method分离,在Koa中我们可以使用如下两种方式。

  • 方式一:根据request自己来判断。
  • 方式二:使用第三方路由中间件。

如果我们在开发中不使用路由中间件来开发,我们需要像如下这种方式来判断路由进行匹配不同的接口。

js 复制代码
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 = "登录成功,欢迎回来~"
  }
})

是不是看起来挺乱的,代码可读性和可维护性并不好,所以一般我们会使用路由库来做这些操作。

三.路由的使用


koa官方并没有给我们提供路由的库,我们可以选择第三方库:koa-router

js 复制代码
npm install @koa/router

然后我们就可以使用路由来完成上述路径和方法的匹配操作。

js 复制代码
const Koa = require("koa")
const koaRouter = require('@koa/router')

// 创建服务器app
const app = new Koa()

// 创建一个路由对象
const userRouter = new koaRouter({ prefix: '/users' })
userRouter.get('/', (ctx, next) => {
  ctx.body = "user list data"
})
userRouter.get('/:id', (ctx, next) => {
  const id = ctx.params.id
  ctx.body = '获取了用户' + id
})
userRouter.post('/', (ctx, next) => { })

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
})

// 让路由中间件生效
app.use(userRouter.routes())
app.use(userRouter.allowedMethods())

// 启动服务器
app.listen(6000, () => {
  console.log("服务启动在6000端口🚀")
})

其中allowedMethods的作用是当我们请求一个不存在的方法的时候服务端会返回如下的内容:

  • 如果我们请求get,那么请求是正常的,因为我们有实现get。
  • 如果我们请求put,delete,patch,那么就会自动报错:Method Not Allowed 状态码405
  • 如果我们请求link,copy,lock那么就会自动报错,Not Implemented,状态码501

四.参数解析:params-query


例如我们的请求地址是 :http://localhost:8000/users/123 然后我们来获取params

js 复制代码
 // 注册路由对象
const useRouter = new KoaRouter({ prefix: '/users' })
// 1.params
useRouter.get('/:id', (ctx, next) => {
  const id = ctx.params.id
  ctx.body = "user list data" + id
})

然后我们对query做解析,比如我们的地址是:http://localhost:8000/login?username=why&password=123

js 复制代码
useRouter.get('/', (ctx, next) => {
  const query = ctx.query
  ctx.body = '用户的query数据' + JSON.stringify(query)
})

五.参数解析:json


比如当我们的请求地址为:http://localhost:8000/login body是json格式:

js 复制代码
{
    "username":"coderwhy",
    "password":13,
}

当在Koa中需要对请求体中的数据进行解析的时候不能直接通过ctx.body或者ctx.request.body进行获取,我们一般会使用第三方插件koa-bodyparser来进行解析,我们可以按照如下进行安装。

js 复制代码
npm install koa-bodyparser

然后我们在我们的app文件中使用一下,就可以解析json格式的数据了。

js 复制代码
 // 使用第三方中间件
app.use(bodyParser())
// 注册路由对象
const useRouter = new KoaRouter({ prefix: '/users' })
useRouter.post('/json', (ctx, next) => {
  const json = ctx.request.body
  ctx.body = JSON.stringify(json)
})

六.参数解析:x-www-form-urlencoded


在上面我们解析了json格式的请求数据,那么接下来我们来解析一下x-www-form-urlencoded格式的数据,我们假定我们的请求地址如下:http://localhost:8000/login 请求体的格式是x-www-form-urlencoded

js 复制代码
useRouter.post('/urlencoded', (ctx, next) => {
  console.log(ctx.request.body)
  ctx.body = "urlencoded"
})

对于urlencoded的解析json的中间件依然是适用的,所以我们可以直接进行解析完成,并不需要另外安装其他的中间件来完成上述任务。

七.参数解析:form-data


接下来我们来解析一下form-data格式的数据,我们假设请求地址为:http://localhost:8000/login body是form-data的格式,对于form-data的格式数据我们需要安装另外一个第三方中间件来解析

js 复制代码
npm install koa-multer

然后我们编写一下代码

js 复制代码
const koaMulter = require("koa-multer")
const upload = koaMulter({})

app.use(upload.any())

useRouter.post('/form-data', (ctx, next) => {
  console.log(ctx.req.body)
  ctx.body = "form-data"
})

八.Multer文件上传


我们在上述内容中了解了Koa框架中如何进行文件的上传,首先我们先实现一下单个文件的上传

js 复制代码
const koaMulter = require("koa-multer")

const upload = koaMulter({
  storage:koaMulter.diskStorage({
    destination(req,file,cb){
      cb(null,'./uploads')
    },
    filename(req,file,cb){
      cb(null,Date.now()+'_'+file.originalname)
    }
  })
})

// 文件上传
useRouter.post('/avatar', upload.single('avatar'), (ctx, next) => {
  ctx.body = "user list data~"
})

然后我们就可以看到文件被正常的上传上去了,其实如果我们不定义图片的后缀也是没有问题的一般情况下图片的后缀不会影响图片的编码,然后我们再来实现下多文件的上传。

js 复制代码
useRouter.post('/photos', upload.array('photos'), (ctx, next) => {
  ctx.body = "more data uploads"
})

九.静态服务器


我们在Express中搭建静态服务器可以直接使用Express内置的相关功能来直接部署静态资源,但是不同的是Koa并没有给我们内置静态资源服务器,我们想要部署我们的静态资源的话我们需要进行使用第三方库,首先我们需要安装以下这个第三方库。

js 复制代码
npm install koa-static

在Koa中部署静态资源的方式和在Express中部署静态资源非常的类似。

js 复制代码
const Koa = require("koa")
const static = require("koa-static")

const app = new Koa()

app.use(static('/uploads'))

app.listen(6000, () => {
  console.log("服务启动在6000端口~")
})

十.数据响应


输出结果:body将响应主题设置为以下之一

  • string : 字符串数据
  • Buffer:Buffer数据
  • Stream:流数据
  • Object || Array :对象或者数组
  • null:不输出任何内容
  • 如果response.status尚未设置,Koa会自动将状态设置为200或者204
js 复制代码
const Koa = require("koa")
const KoaRouter = require("@koa/router")
const fs = require("fs")
const app = new Koa()

const userRouter = new KoaRouter({ prefix: '/users' })

// string
userRouter.get('/string', (ctx, next) => {
  ctx.body = "你好世界~"
})

// buffer
userRouter.get('/buffer', (ctx, next) => {
  ctx.body = Buffer.from("你好世界~")
})

// stream
userRouter.get('/stream', (ctx, next) => {
  const readStream = fs.createReadStream("./uploads/1744290334979_js.png")
  ctx.type = "image/jpg"
  ctx.body = readStream
})

// array/object
userRouter.get("/array", (ctx, next) => {
  ctx.body = ['a', 'b', 'c']
})

// null
userRouter.get('/null', (ctx, next) => {
  ctx.body = null // 为null会自动设置为204
})


app.use(userRouter.routes())
app.use(userRouter.allowedMethods())

app.listen(6000, () => {
  console.log("服务器启动在6000端口~")
})

十一.错误的处理


在Koa中我们也可以像在Express中一样进行全局的错误处理,接下来我们可以看下如何在Koa中进行错误处理。

js 复制代码
app.use((ctx, next) => {
  ctx.app.emit('error', new Error('哈哈哈'), ctx)
})

app.on('error', (err, ctx) => {
  console.log(err.message)
  ctx.response.body = "哈哈哈"
})

十二.总结


这篇文章到这里就结束了🌸,这篇文章我们大概讲解了一下Koa的使用方式,以及大致了解了Koa和Express之间的区别,Koa的特点是比较轻量,基本上所有的东西都需要通过第三方插件来解决,但是Koa也有自己更加强大的地方,在后续我们详细了解Koa和Express之间的区别的时候再交流学习。

相关推荐
若梦plus几秒前
异步编程思想
前端·javascript·程序员
张开心_kx1 分钟前
面试官又问我是否了解虚拟DOM?
前端·javascript·react.js
海底火旺1 分钟前
JavaScript对象存在性检查:从原理到陷阱的完全指南
前端·javascript
bug_kada1 分钟前
深入理解 Vue 3 中的 watch 和 watchEffect
前端·vue.js
_清浅1 分钟前
Servlet
前端·javascript
宇宙的有趣2 分钟前
当 TypeScript 类型嵌套超过了 100 层
前端·typescript
_Le_2 分钟前
SVG,你需要知道的......
前端·svg
JYeontu4 分钟前
echarts绘制一个名山地图
前端·javascript·echarts
阿廖沙10245 分钟前
【十倍生产力】用Cursor+ChatGPT做技术调研,一天时间搞定Electron调用macOS OCR文字提取能力
前端·electron
码觉客8 分钟前
如何使用chrome-extension-boilerplate-react-vite 从零开始开发一款浏览器插件
前端