• 作者:老汪软件技巧
  • 发表时间:2024-08-18 07:03
  • 浏览量:

一.写在前面

大家好我是一溪风月一名前端程序员,我们在上篇文章分享了Express框架的核心用法,接下来我们将会学习使用Koa框架,Koa被称为Node的下一代框架,并且很多企业级框架也是基于Koa的,比如阿里的midway就是基于koa来构建的企业级服务端框架,相对于Express框架Koa更加的轻量易用,并且完全符合洋葱模型,目前受到了很多开发者的欢迎,既然这样那么就让我们一起来学习一下吧,如果你觉得这篇文章对你有帮助,请不要吝啬你的如果你对Node服务端的知识比较感兴趣可以关注我的专栏Node服务端和我一起学习,一起进步。

二.认识Koa框架

前端我们已经学习了Express,另外一个非常流行的Node Web服务器框架就是Koa,根据官方的介绍,Koa是Node的下一代的Web框架,事实上,koa是express同一个团队开发的一个新的Web框架,目前团队的核心开发者TJ的主要精力也在维护koa,express已经交给团队维护了,koa旨在为Web应用程序和API提供更小,更丰富和更强大的能力,相对于express具有更强大的异步处理能力,同时koa的核心代码只有1600+行,是一个更加轻量级的框架,我们可以根据需要安装和使用中间件。

三.Koa初体验

事实上在我们学习了express框架之后再学习koa会变得非常的容易,那么就让我们使用Koa来创建一个接口,Koa也是基于中间件来完成请求操作的,首先我们需要像使用Express一样先安装一下Koa框架

# 初始化项目
npm init -y
# 安装Koa框架依赖
npm install koa

然后我们搭建一个Koa的基本使用过程。

const Koa = require("koa")
// 创建koa对象
const app = new Koa()
// 注册中间件
// koa中间件有两个参数ctx/next
app.use((ctx, next) => {
  console.log("匹配到了中间件")
  ctx.body = "Hello Koa"
})
// 监听端口
app.listen(3000, () => {
  console.log("服务启动在3000端口")
})

然后我们使用apifox来访问下看下返回结果。

四.Koa中间件参数ctx解析

在Koa中和Express不同的是,在Koa中中间件提供了两个参数分别是ctx和next其实ctx这个参数其实包含了express中请求和响应的对象的,既包含请求也包含响应,next和express中的next在同步状态下是一样的。

app.use((ctx, next) => {
  console.log("匹配到了中间件")
  console.log(ctx.request, "koa封装的请求对象") // koa封装的请求对象
  console.log(ctx.req, "node自身的请求对象") // node自身的请求对象
  console.log(ctx.response, "koa封装的响应对象") // koa封装的响应对象
  console.log(ctx.res, "node自身的响应对象") // koa封装的响应对象
  // 其他属性
  console.log(ctx.query)
  console.log(ctx.path)
  ctx.body = "Hello Koa"
})

注意:在ctx下有两个属性分别是request和req 其中request是Koa封装的请求对象,但是req其实是Node中的http模块提供的对象,响应对象也是如此response是koa封装的对象,res是Node提供的返回对象。

五.Koa的中间件

koa通过创建的app对象,注册中间件只能通过use方法,Koa并没有提供methods的方式来注册中间件,也没有提供path中间件来匹配路径,但是真实开发中我们如何将路径和method分离呢?

方式一:根据request自己来判断(非常麻烦,开发中不会这样使用)

const Koa = require("koa")
const app = new Koa()
// 创建中间件
app.use((ctx, next) => {
  if (ctx.path === "/user") {
    if (ctx.method === "GET") {
      ctx.body = "user dataList~"
    }
  } else if (ctx.path === "/home") {
    if (ctx.method === "POST") {
      ctx.body = "home dataList~"
    }
  } else if (ctx.path === "/login") {
    if (ctx.method === "POST") {
      ctx.body = "登录成功,欢迎回来~"
    }
  }
})
app.listen(3000, () => {
  console.log("服务启动在3000端口")
})

方式二:使用第三方路由中间件,在Koa中官方并没有给我们提供路由,所以我们需要手动安装一个路由,

npm install @koa/router

然后我们使用路由来实现上述的内容。

const Koa = require("koa")
const KoaRouter = require("@koa/router")
const app = new Koa()
// 创建路由对象
const useRouter = new KoaRouter({
  prefix: "/user" // 路由前缀
})
// query参数方式
useRouter.get('/', (ctx, next) => {
  ctx.body = "user list data"
})
// params参数方式
useRouter.get("/:id", (ctx, next) => {
  const id = ctx.params.id
  ctx.body = `user id: ${id}`
})
// post请求方式
useRouter.post("/", (ctx, next) => {
  ctx.body = "创建用户成功"
})
useRouter.delete("/:id", (ctx, next) => {
  const id = ctx.params.id
  ctx.body = `delete user id: ${id}`
})
useRouter.patch("/:id", (ctx, next) => {
  const id = ctx.params.id
  ctx.body = `update user id:${id}`
})
// 让路由生效
app.use(useRouter.routes())
// 对于没有封装过的进行返回不支持
app.use(useRouter.allowedMethods())
app.listen(3000, () => {
  console.log("服务启动在3000端口")
})

注意:allowedMethods用于判断某一个method是否支持,如果我们并没有使用某个路由,则会返回方法不支持。

在开发中我们最好是创建一个user.router.js文件来专门的管理自己的路由,避免代码的混乱难以维护。

const KoaRouter = require("@koa/router")
// 创建路由对象
const useRouter = new KoaRouter({
  prefix: "/user" // 路由前缀
})
// query参数方式
useRouter.get('/', (ctx, next) => {
  ctx.body = "user list data"
})
// params参数方式
useRouter.get("/:id", (ctx, next) => {
  const id = ctx.params.id
  ctx.body = `user id: ${id}`
})
// post请求方式
useRouter.post("/", (ctx, next) => {
  ctx.body = "创建用户成功"
})
useRouter.delete("/:id", (ctx, next) => {
  const id = ctx.params.id
  ctx.body = `delete user id: ${id}`
})
useRouter.patch("/:id", (ctx, next) => {
  const id = ctx.params.id
  ctx.body = `update user id:${id}`
})
module.export = useRouter

六.Koa解析客户端的5种参数

参数解析:get的请求方式params和query

// get params方式
useRouter.get("/:id", (ctx, next) => {
  const id = ctx.params.id
  ctx.body = `userList data~${id}`
})
// get query方式
useRouter.get("/", (ctx, next) => {
  console.log(ctx.request.query)
  ctx.body = "Hello Koa"
})

参数解析:post的请求方式json:解析post请求在koa中需要安装 koa-bodyparser来帮助解析

npm install koa-bodyparser

安装完毕之后我们直接在普通中间件中使用

 // post json方式
useRouter.post("/json", (ctx, next) => {
  console.log(ctx.request.body)
  ctx.body = "Hello Koa"
})

参数解析:post请求方式*x-www-form-urlencoded* 和 json 一样

 // post x-www-form-urlencoded
useRouter.post("/urlencoded", (ctx, next) => {
  console.log(ctx.request.body)
  ctx.body = "Hello Koa"
})

参数解析:post请求方式form-data:解析post请求的form-data需要使用

npm install @koa/multer multer

然后就可以进行formdata的参数解析了,这里展示5种解析的代码,感兴趣的小伙伴可以复制下来跑一跑。

const Koa = require("koa")
const KoaRouter = require("@koa/router")
const koaBodyParser = require("koa-bodyparser")
const multer = require("@koa/multer")
const app = new Koa()
/**
* 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
*/
app.use(koaBodyParser()) // 用来解析post请求
const upload = multer({
  dest: "./uploads"
})
// 创建路由对象
const useRouter = new KoaRouter({
  prefix: "/user" // 路由前缀
})
// get params方式
useRouter.get("/:id", (ctx, next) => {
  const id = ctx.params.id
  ctx.body = `userList data~${id}`
})
// get query方式
useRouter.get("/", (ctx, next) => {
  console.log(ctx.request.query)
  ctx.body = "Hello Koa"
})
// post json方式
useRouter.post("/json", (ctx, next) => {
  console.log(ctx.request.body)
  ctx.body = "Hello Koa"
})
// post x-www-form-urlencoded
useRouter.post("/urlencoded", (ctx, next) => {
  console.log(ctx.request.body)
  ctx.body = "Hello Koa"
})
// post form-data
useRouter.post("/form-data", upload.single("file"), (ctx, next) => {
  console.log(ctx.request.body)
  ctx.body = "Hello Koa"
})
// 让路由生效
app.use(useRouter.routes())
// 对于没有封装过的进行返回不支持
app.use(useRouter.allowedMethods())
app.listen(3000, () => {
  console.log("Server启动在3000端口")
})

七.文件上传

我们知道Multer不仅仅可以支持form-data的请求,还可以实现文件的上传,并且可以对文件进行命名,编写方式完全和Express基本一样。

const Koa = require("koa")
const KoaRouter = require("@koa/router")
const koaBodyParser = require("koa-bodyparser")
const multer = require("@koa/multer")
const app = new Koa()
app.use(koaBodyParser()) // 用来解析post请求
const storage = multer.diskStorage({
  destination: (ctx, file, cb) => {
    cb(null, "./uploads")
  },
  filename: (ctx, file, cb) => {
    cb(null, file.originalname)
  }
})
const upload = multer({
  storage
})
// 创建路由对象
const useRouter = new KoaRouter({
  prefix: "/user" // 路由前缀
})
// post form-data
useRouter.post("/form-data", upload.single("file"), (ctx, next) => {
  console.log(ctx.request.file)
  ctx.body = "文件上传成功"
})
// 多文件上传仅需upload.array("files")即可
// 让路由生效
app.use(useRouter.routes())
// 对于没有封装过的进行返回不支持
app.use(useRouter.allowedMethods())
app.listen(3000, () => {
  console.log("Server启动在3000端口")
})

八.静态文件服务器

Koa和Express框架一样可以作为文件服务器,为客户端提供文件访问服务,在Koa需要安装koa-static这个包来实现。

npm install koa-static

然后我们就可以像Express一样来部署自己的静态服务器了,然后通过访问当前服务端口路径查看静态资源。

const Koa = require("koa")
const static = require("koa-static")
const app = new Koa()
// 访问localhost:3000当前端口下的static目录下的文件
app.use(static('./static'))
// 监听端口
app.listen(3000, () => {
  console.log("静态服务器启动成功")
})

九.数据的响应

在Koa框架中输出结果是通过body来响应的,body将响应主体设置为以下之一

string:字符串数据

Buffer:Buffer数据

Stream:流数据

Object||Array:对象或者数组

null:不能输出任何内容

提示:如果response.status尚未设置,koa会自动将状态设置为200或者204。

useRouter.get('/', (ctx, next) => {
  // body的类型是字符串类型
  ctx.body = "user list data"
  
  // body类型是buffer类型
  ctx.body = Buffer.from("user list data")
  
  // body类型是Stream类型
  const readStream = fs.createReadStream("./static/index.html")
  ctx.type = "text/html"
  ctx.body = readStream
  
  // body类型是Array或者object
  ctx.body = {
    name: "张三",
    age: 18
  }
  
  // body是null类型
  ctx.body = null
})

十.Koa错误的处理

十一.总结

本篇文章到这里就结束了,这篇文章我们学习了Koa框架,Koa框架相对于Express框架更加的轻量,目前也受很多开发者的欢迎,这篇文章我们学习了Koa常见的参数解析,路由配置等等,这些知识是我们后续使用Koa开发项目的前提,希望感兴趣的小伙伴能够好好掌握。


上一条查看详情 +ArkUI开发 - 实现简易的方法hook框架
下一条 查看详情 +没有了