Koa 参数解析和数据响应

104 阅读4分钟

参数解析

动态路由参数

 import Koa from 'koa'
 import Router from '@koa/router'
 ​
 const app = new Koa()
 // 不传路由前缀,默认就是根路由 /
 const router = new Router()
 ​
 // 请求路径为 /Klaus/20
 router.get('/:name/:age', (ctx) => {
   // 属性值都是字符串类型值
   console.log(ctx.params) // { name: 'Klaus', age: '20' }
   ctx.body = `Hello ${ctx.params.name}, you are ${ctx.params.age} years old`
 })
 ​
 app.use(router.routes()).use(router.allowedMethods())
 ​
 app.listen(3000)

查询字符串

 import Koa from 'koa'
 import Router from '@koa/router'
 ​
 const app = new Koa()
 // 不传路由前缀,默认就是根路由 /
 const router = new Router()
 ​
 // 请求路径为 /user?name=Tom&age=23
 router.get('/user', (ctx) => {
   console.log(ctx.query) // { name: 'Tom', age: '23' }
   ctx.body = `Hello ${ctx.query.name}, you are ${ctx.query.age} years old`
 })
 ​
 app.use(router.routes()).use(router.allowedMethods())
 ​
 app.listen(3000)

JSON格式和urlencode参数

 import Koa from 'koa'
 import Router from '@koa/router'
 import bodyParser from 'koa-bodyparser'
 ​
 const app = new Koa()
 ​
 // 挂载bodyParser中间件
 // 1. 可以自动解析请求体中的JSON对象和urlencoded数据
 // 2. 将结果挂载到 ctx.request.body 上
 app.use(bodyParser())
 ​
 const router = new Router({ prefix: '/user' })
 ​
 // 传入的 json数据为 {"name": "Tom", "age": 30}
 router.post('/json', (ctx) => {
   console.log(ctx.request.body) // { name: 'Tom', age: 30 }
   ctx.body = ctx.request.body
 })
 ​
 // 传入的 urlencoded数据为 name=Tom&age=30
 router.post('/urlencoded', (ctx) => {
   // 会自动转对象,但属性值为字符串 => url是字符串值,无法确定你要的是数字还是值以为数值的字符串
   console.log(ctx.request.body) // { name: 'Tom', age: '30' }
   ctx.body = ctx.request.body
 })
 ​
 app.use(router.routes()).use(router.allowedMethods())
 ​
 app.listen(3000)

POST请求的FormData格式

解析 FormData 格式数据需要通过 multer

Koa基于multer进行了二次封装,提供了中间件@koa/multer

@koa/multer会自动将将表单数据解析出来并自动挂载到ctx.request.body

koa-router一样,早期叫koa-multer,已经停止维护,推荐用@koa/multer。

 pnpm install @koa/multer multer
 import Koa from 'koa'
 import Router from '@koa/router'
 ​
 // 本质基于 multer 实现,使用方式和 multer 一样
 import multer from '@koa/multer'
 ​
 const app = new Koa()
 const router = new Router({ prefix: '/user' })
 ​
 // 表单数据并不是所有接口都需要解析的,所以一般作用于单个接口
 // 和 express 一样,路径中间件的类型为 router.<method>(path, ...middlewares)
 // 对应中间件会被加入数组中,并被依次执行
 router.post('/form', multer().any(), (ctx) => {
   console.log(ctx.request.body)
   ctx.body = ctx.request.body
 })
 ​
 app.use(router.routes()).use(router.allowedMethods())
 ​
 app.listen(3000)

文件上传

 import Koa from 'koa'
 import Router from '@koa/router'
 import path from 'node:path'
 // 底层基于 multer 实现,使用方式和 multer 一样
 // 可以用于解析表单数据,也可以用于解析文件上传
 import multer from '@koa/multer'
 ​
 const app = new Koa()
 const router = new Router({ prefix: '/user' })
 ​
 const storage = multer.diskStorage({
   destination: function (req, file, cb) {
     cb(null, 'uploads')
   },
   filename: function (req, file, cb) {
     cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname))
   }
 })
 ​
 const upload = multer({ storage: storage })
 ​
 router.post('/upload', upload.single('avatar'), (ctx) => {
   // 凡是 ctx.request 和 ctx.response 上存在的属性 都可以通过 ctx 进行访问
   // 包括 multer 解析后挂载的文件信息 => 这是 @koa/multer 额外进行实现的
   // 单个文件信息挂载到 ctx.file 上,多个文件信息挂载到 ctx.files 上
   // 但有一个特别的: ctx.body 是 ctx.response.body
   // 而请求体的body 只能通过ctx.request.body 来获取
   console.log(ctx.file)
   ctx.body = '上传成功'
 })
 ​
 app.use(router.routes()).use(router.allowedMethods())
 ​
 app.listen(3000, () => {
   console.log('Server is running on port 3000')
 })

数据响应

返回文本内容

 import Koa from 'koa'
 ​
 const app = new Koa()
 ​
 app.use(ctx => {
   // 返回文本数据 并设置响应头为 text/plain
   ctx.body = 'Hello World'
   // 可以通过 ctx.set 来设置响应头
   // ctx.set('Content-Type', 'text/plain')
 })
 ​
 app.listen(3000)

返回二进制

 import Koa from 'koa'
 ​
 const app = new Koa()
 ​
 app.use(ctx => {
   // 返回文本数据 并设置响应头为 application/octet-stream
   ctx.body = Buffer.from('Hello World')
 })
 ​
 app.listen(3000)

返回数据流

 import Koa from 'koa'
 import fs from 'fs'
 ​
 const app = new Koa()
 ​
 app.use(ctx => {
   const stream = fs.createReadStream('./uploads/avatar-1750581078613.jpeg')
   // 设置响应头
   // 不设置,默认当做 application/octet-stream 来处理, 此时客户端会自动按照 8位一个字节来处理
   // 设置为 image/jpeg 后,Content-Type 会自动设置为 image/jpeg
   // 此时客户端会按照 image/jpeg 来处理,并最终显示为图片
 ​
   // koa 通过 ctx.set(key, value) 来设置响应头
   // 而 Content-Type 比较特殊,存在简写方式 ctx.type
   // ctx.type = 'image/jpeg' 实际等价于 ctx.set('Content-Type', 'image/jpeg')
   ctx.type = 'image/jpeg'
   // 设置响应体
   ctx.body = stream
 })
 ​
 app.listen(3000)

返回JSON

 import Koa from 'koa'
 ​
 const app = new Koa()
 ​
 app.use(ctx => {
   ctx.body = {
     name: '张三',
     age: 20,
     gender: '男',
     email: 'zhangsan@example.com',
     phone: '12345678901',
     address: '北京市海淀区'
   }
 })
 ​
 app.listen(3000)

什么都不返回

 import Koa from 'koa'
 ​
 const app = new Koa()
 ​
 app.use(ctx => {
   // 没有任何响应头,koas会自动设置状态码为 204 No Content
   // 默认情况下,有内容返回 200,无内容返回 204
   ctx.body = null
 })
 ​
 app.listen(3000)

手动设置状态码

 import Koa from 'koa'
 ​
 const app = new Koa()
 ​
 app.use(ctx => {
   // 设置状态码 为 201 Created
   ctx.status = 201
   // 设置响应体
   ctx.body = 'Hello World'
 })
 ​
 app.listen(3000)