Koa (下一代web框架) 【Node.js进阶】

news2024/11/10 20:43:14

koa (中文网) 是基于 Node.js 平台的下一代 web 开发框架,致力于成为应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石;

利用 async 函数 丢弃回调函数,并增强错误处理,koa 没有任何预置的中间件,可快速的编写服务端应用程序。

切入点

    • 一、核心概念
    • 二、初识 koa
    • 三、路由
      • 1、安装依赖:@koa/router
      • 2、定义路由
    • 四、中间件
      • 中间件是如何执行的?
    • 五、常见获取值的几种方式
      • 1、在 params 中取值
      • 2、在 query 中取值
      • 3、获取 header 中的参数
      • 4、 获取 body 中的数据
    • 六、创建 RESTful 接口


一、核心概念

  • Koa Application(应用程序)
  • Context(上下文,可简化为 ctx)
  • Request(请求)、Response(响应)

二、初识 koa

# 创建一个 app-koa 的文件夹,作为 koa 工程根目录
mkdir app-koa

# 进入创建的文件夹
cd app-koa

# 初始化 package.json
npm init -y

# 安装 koa
npm i koa

Tips: 可以在 package.json 中查看安装的所有依赖

在工程目录里创建一个 app.js

const Koa = require('koa') // 引入 koa
const app = new Koa() // 实例化 koa

app.use(ctx => {
  ctx.body = 'hello koa'
})

// 启动应用程序  参数:端口号
app.listen(3000)

在终端中使用 node app.js 命令【注意:执行命令时,终端的路径必须指向当前程序目录】

打开浏览器访问:http://localhost:3000 此时浏览器中就会输出 hello koa

在这里插入图片描述

上面代码虽然轻松实现了一个 web 服务器,但是返回的数据和所请求都是固定的;
并不适应真实的业务场景,比如:获取请求接口时的参数、方法、修改一次代码就要在终端中重新运行启动命令等;

由于使用的 node app.js 启动,所以每次更改都要重新启动,这样给我们开发带来了极大的不便利,所以我们可以使用一些第三方依赖来自动监听文件的变化并重新启动,开发环境可以使用 nodemon ,首先安装 npm i nodemon -D,也可以全局安装此依赖。生产环境的话可以使用 pm2 安装之后在package.jsonscripts 中添加启动方式。如下:

{
  "name": "app-koa",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "nodemon app.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "koa": "^2.15.3"
  },
  "devDependencies": {
    "nodemon": "^2.0.7"
  }
}

在终端中执行命令: npm run dev 这样就不用我们每次修改都重新启动,执行之后就会在终端中提示,如下:

在这里插入图片描述

三、路由

1、安装依赖:@koa/router

@koa/router

npm i @koa/router

2、定义路由

  1. app.js 中引入 @koa/router ,然后再实例化

    const Router = require('@koa/router')
    const router = new Router({ prefix: '/api/v1' }) // 实例化的时候可以自定义一个接口前缀
    
  2. 注册 router

    app.use(router.routes()).use(router.allowedMethods())
    
  3. 定义接口

    router.get('/', async ctx => {
      ctx.body = {
        status: 200,
        message: 'hello @koa/router'
      }
    })
    
    router.get('/user', async ctx => {
      ctx.body = {
        status: 200,
        message: 'success',
        data: {
          nickname: 'Simon',
          age: 18,
          jobs: '前端攻城狮',
          skills: '搬砖'
        }
      }
    })
    

app.js 完整代码如下:

const Koa = require('koa')
const Router = require('@koa/router')
const app = new Koa()
const router = new Router({ prefix: '/api/v1' }) // 添加接口前缀

router.get('/', async ctx => {
  ctx.body = {
    status: 200,
    message: 'hello @koa/router'
  }
})

router.get('/user', async ctx => {
  ctx.body = {
    status: 200,
    message: 'success',
    data: {
      nickname: 'Simon',
      age: 18,
      jobs: '前端攻城狮',
      skills: '搬砖'
    }
  }
})

app.use(router.routes()).use(router.allowedMethods())
// 启动应用程序  参数:端口号
app.listen(3000)

在浏览器中请求: http://localhost:3000/api/v1http://localhost:3000/api/v1/user,结果如下图:

在这里插入图片描述

在这里插入图片描述

四、中间件

中间件其实就是一个个函数,通过 app.use() 注册;

在 koa 中只会自动执行第一个中间件,后面的都需要我们自己调用,koa 在执行中间件的时候都会携带两个参数 context (可简化为ctx)和 nextcontext 是 koa 的上下文对象,next 就是下一个中间件函数;

这也就是洋葱模型,所谓洋葱模型,就是指每一个 Koa 中间件都是一层洋葱圈,它即可以掌管请求进入,也可以掌管响应返回。

换句话说:外层的中间件可以影响内层的请求和响应阶段,内层的中间件只能影响外层的响应阶段。

koa洋葱模型

执行顺序按照 app.use() 的顺序执行,中间件可以通过 await next() 来执行下一个中间件,同时在最后一个中间件执行完成后,依然有恢复执行的能力。

即,通过洋葱模型,await next() 控制调用 “下游”中间件,直到 “下游”没有中间件且堆栈执行完毕,最终流回“上游”中间件。

下面这段代码的结果就能很好的诠释,示例:

// app.js

const Koa = require('koa')
const app = new Koa()

app.use(async (ctx, next) => {
  console.log(`this is a middleware 1`)
  await next()
  console.log(`this is a middleware 1 end `)
})

app.use(async (ctx, next) => {
  console.log(`this is a middleware 2`)
  await next()
  console.log(`this is a middleware 2 end `)
})

app.use(async (ctx, next) => {
  console.log(`this is a middleware 3`)
  await next()
  console.log(`this is a middleware 3 end `)
})

app.listen(3000)

运行结果如下:

this is a middleware 1
this is a middleware 2
this is a middleware 3
this is a middleware 3 end
this is a middleware 2 end
this is a middleware 1 end

中间件是如何执行的?

// 通过 createServer 方法启动一个 Node.js 服务
listen(...args) {
  const server = http.createServer(this.callback());
  return server.listen(...args);
}

Koa 框架通过 http 模块的 createServer 方法创建一个 Node.js 服务,并传入 this.callback() 方法。

this.callback() 方法源码精简实现如下:

function compose(middleware) {
  // 这里返回的函数,就是上文中的 fnMiddleware
  return function (context, next) {
    let index = -1
    return dispatch(0)

    function dispatch(i) {
      if (i <= index) return Promise.reject(new Error('next() called multiple times'))
      index = i
      // 取出第 i 个中间件为 fn
      let fn = middleware[i]

      if (i === middleware.length) fn = next

      // 已经取到了最后一个中间件,直接返回一个 Promise 实例,进行串联
      // 这一步的意义是保证最后一个中间件调用 next 方法时,也不会报错
      if (!fn) return Promise.resolve()

      try {
          // 把 ctx 和 next 方法传入到中间件 fn 中,并将执行结果使用 Promise.resolve 包装
          // 这里可以发现,我们在一个中间件中调用的 next 方法,其实就是dispatch.bind(null, i + 1),即调用下一个中间件
          return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
      } catch (err) {
          return Promise.reject(err)
      }
    }
  }
}

callback() {
  // 从 this.middleware 数组中,组合中间件
  const fn = compose(this.middleware);

  // handleRequest 方法作为 `http` 模块的 `createServer` 方法参数,
  // 该方法通过 `createContext` 封装了 `http.createServer` 中的 `request` 和 `response`对象,并将这两个对象放到 ctx 中
  const handleRequest = (req, res) => {
    const ctx = this.createContext(req, res);
    // 将 ctx 和组合后的中间件函数 fn 传递给 this.handleRequest 方法
    return this.handleRequest(ctx, fn);
  };

  return handleRequest;
}

handleRequest(ctx, fnMiddleware) {
  const res = ctx.res;
  res.statusCode = 404;
  const onerror = err => ctx.onerror(err);
  const handleResponse = () => respond(ctx);
  // on-finished npm 包提供的方法,该方法在一个 HTTP 请求 closes,finishes 或者 errors 时执行
  onFinished(res, onerror);
  // 将 ctx 对象传递给中间件函数 fnMiddleware
  return fnMiddleware(ctx).then(handleResponse).catch(onerror);
}

将 Koa 一个中间件组合和执行流程梳理为以下步骤:

  • 通过 compose 方法组合各种中间件,返回一个中间件组合函数 fnMiddleware
  • 请求过来时,会先调用 handleRequest 方法,该方法完成;
  • 调用 createContext 方法,对该次请求封装出一个 ctx 对象;
  • 接着调用 this.handleRequest(ctx, fnMiddleware) 处理该次请求。
  • 通过 fnMiddleware(ctx).then(handleResponse).catch(onerror) 执行中间件。

五、常见获取值的几种方式

1、在 params 中取值

// 前端请求
await axios.post('http://localhost:3000/api/v1/user/1')

// 服务端接收
router.post('/user/:id',async ctx => {
  // 获取 url 的 id
  cosnt { id } = ctx.params;  // { id: 1 }
})

2、在 query 中取值

也就是获取问号后面的参数

// 前端请求
await axios.post('http://localhost:3000/api/v1/user?name=Simon&age=18')

// 服务端接收
router.post('/user', async ctx => {
  // 获取 url 的 name & age
  const { name, age } = ctx.request.query; // { name: Simon, age: 18 }
})

3、获取 header 中的参数

// 前端 请求接口时设置请求头
axios
  .post(
    'http://localhost:3000/api/v1/user?name=Simon&age=18',
    {
      headers: {
        Author: 'token'
      }
    }
    //......
  )
  .then(res => console.log('res:', res))

// 在服务端 获取
router.post('/user', async ctx => {
  // 获取 header 中的 Author
  const { Author } = ctx.request.header // { Author: 'token' }
})

4、 获取 body 中的数据

在服务端获取 body 中的一些数据只能用一些外部的插件;如:koa-bodykoa-bodyparser 等等。

就以 koa-body 为例,首先安装 npm i koa-body,再引入:

// 前端发起请求有两种传参方式,一种是 json,另一种是 fromData;
// 以 json 为例
axios.post('http://localhost:3000/api/v1/user', {name: 'Simon', age: 18}).then(res => {
    console.log('res:', res)
});

// 服务端
// 引入 koa-body 插件
const body = require('koa-body);

// 然后在注册中间件:
app.use(body());

// 在服务端获取:
router.post('/user', async ctx => {
    const res = ctx.request.body; // { name: 'Simon', age: 18 }
});

六、创建 RESTful 接口

const Koa = require('koa')
const Router = require('@koa/router')
const koaBody = require('koa-body')
const app = new Koa()
const router = new Router({ prefix: '/api/v1' })

router.get('/', async ctx => {
  ctx.body = {
    status: 200,
    message: 'hello @koa/router'
  }
})

router.get('/user', async ctx => {
  ctx.body = {
    status: 200,
    message: 'success',
    data: {
      query: ctx.query,
      nickname: 'Simon',
      age: 18,
      jobs: '前端攻城狮',
      skills: '搬砖'
    }
  }
})

router.get('/user/:id', async ctx => {
  const { id } = ctx.params
  ctx.body = {
    status: 200,
    message: 'success',
    data: {
      id,
      nickname: 'Simon',
      age: 18,
      jobs: '前端攻城狮',
      skills: '搬砖'
    }
  }
})

router.post('/user', async ctx => {
  const { name, age } = ctx.request.body
  ctx.body = {
    status: 200,
    data: {
      name,
      age
    }
  }
})

// koa-body 中间件的引入顺序必须在 @koa/router 之前,否则获取不了 post 请求携带的数据
app.use(koaBody()).use(router.routes()).use(router.allowedMethods())

app.listen(3000)

希望上面的内容对你的工作学习有所帮助!欢迎各位一键三连哦~

各位 加油!

原创不易,还希望各位大佬支持一下 \textcolor{blue}{原创不易,还希望各位大佬支持一下} 原创不易,还希望各位大佬支持一下

👍 点赞,你的认可是我创作的动力! \textcolor{green}{点赞,你的认可是我创作的动力!} 点赞,你的认可是我创作的动力!

⭐️ 收藏,你的青睐是我努力的方向! \textcolor{green}{收藏,你的青睐是我努力的方向!} 收藏,你的青睐是我努力的方向!

✏️ 评论,你的意见是我进步的财富! \textcolor{green}{评论,你的意见是我进步的财富!} 评论,你的意见是我进步的财富!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2145539.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DevExpress WinForms v24.1新版亮点:升级的HTML CSS支持

DevExpress WinForms拥有180组件和UI库&#xff0c;能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForms能完美构建流畅、美观且易于使用的应用程序&#xff0c;无论是Office风格的界面&#xff0c;还是分析处理大批量的业务数据&#xff0c;它都能轻松胜…

mavlink源码编译及示例使用

1.克隆源码: git clone https://github.com/mavlink/mavlink.git --recursive 克隆成功: 2.克隆python3与pip已安装 3.安装依赖: python3 -m pip install -r pymavlink/requirements.txt

[JavaEE]———进程、进程的数据结构、进程的调度

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯&#xff0c;你们的点赞收藏是我前进最大的动力&#xff01;&#xff01;希望本文内容能帮到你&#xff01; 目录 一&#xff1a;操作系统 1&#xff1a;操作系统的定位和功能 2&#xff1a;多任务操作系统 3&#xff1a…

硬件开篇——体系架构

1、驱动开发分类&#xff1a; 裸机驱动&#xff08;无操作系统&#xff09;——由寄存器控制&#xff1b;Linux驱动。 硬件&#xff1a; 计算机系统&#xff1a; 计算机架构&#xff1a;①冯诺依曼&#xff08;指令、数据一起&#xff09;②哈佛&#xff08;指令、数据分开&a…

【BoF】《Bag of Freebies for Training Object Detection Neural Networks》

arXiv-2019 https://github.com/dmlc/gluon-cv 文章目录 1 Background and Motivation2 Related Work3 Advantages / Contributions4 Method4.1 Visually Coherent Image Mixup for Object Detection4.2 Classification Head Label Smoothing4.3 Data Preprocessing4.4 Traini…

如何使用ssm实现理财通的设计与实现

TOC ssm638理财通的设计与实现jsp 第一章 绪论 1.1 选题背景 目前整个社会发展的速度&#xff0c;严重依赖于互联网&#xff0c;如果没有了互联网的存在&#xff0c;市场可能会一蹶不振&#xff0c;严重影响经济的发展水平&#xff0c;影响人们的生活质量。计算机的发展&am…

功能测试干了三年,快要废了。。。

8年前刚进入到IT行业&#xff0c;到现在学习软件测试的人越来越多&#xff0c;所以在这我想结合自己的一些看法给大家提一些建议。 最近聊到软件测试的行业内卷&#xff0c;越来越多的转行和大学生进入测试行业&#xff0c;导致软件测试已经饱和了&#xff0c;想要获得更好的待…

Linux提升篇-服务器BIOS介绍

目录 前言BIOS 概述常用配置进入 BIOS 界面查询 iBMCIP 地址设置 BIOS 系统日期和时间设置服务器启动方式 前言 以下bios介绍适用于大部分2020年之后的服务器&#xff0c;包括Huawei系的鲲鹏CPU架构服务器&#xff0c;X86系也可参考&#xff0c;大部分配置项是一致的。 BIOS …

【Java】线程的同步——synchronized、ReentrantLock

对同一个线程&#xff0c;能否在获取到锁以后继续获取同一个锁? 答案是肯定可以获取同一个锁。因为JVM 允许同一个线程重复获取同一个锁&#xff0c;这种能被同一个线程反复获取的锁&#xff0c;就叫做可重入锁。 一、synchronized同步锁 在 Java中synchronized 同步锁…

HbuilderX自定义快捷键

打开快捷键设置&#xff1a;工具->自定义快捷键 复制想要修改的快捷键设置 修改后记得保存 可以通过该方法找到对应功能的系统默认快捷键

[数据集][目标检测]智慧养殖场肉鸡健康状态检测数据集VOC+YOLO格式4657张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;4657 标注数量(xml文件个数)&#xff1a;4657 标注数量(txt文件个数)&#xff1a;4657 标注…

用ASR PRO离线语音芯片和月饼盒做一个会跑会跳会说话的机器狗

中秋节刚过&#xff0c;大家月饼盒应该还有&#xff0c;不要扔&#xff0c;可以做点小玩意。 机器狗的创意来自B站石桥北的视频&#xff0c;他使用了一块ESP32芯片和打印件加四个舵机实现&#xff0c;应该说是比较复杂的&#xff0c;需要有3D打印机打印外壳&#xff0c;还得会…

Hadoop的一些高频面试题 --- hdfs、mapreduce以及yarn的面试题

文章目录 一、HDFS1、Hadoop的三大组成部分2、本地模式和伪分布模式的区别是什么3、什么是HDFS4、如何单独启动namenode5、hdfs的写入流程6、hdfs的读取流程7、hdfs为什么不能存储小文件8、secondaryNameNode的运行原理9、hadoop集群启动后离开安全模式的条件10、hdfs集群的开机…

TortoiseSVN图标不显示的解决

解决办法一&#xff1a;修改svn软件的图标设置 1、选中一个文件夹或在桌面空白处&#xff0c;右击进入svn的setting 2、进入setting->Icon Overlays&#xff0c;Status cache选择Default或shell&#xff0c;然后点击应用 3、查看文件&#xff0c;图标可以正常显示 解决办法…

ubuntu下载安装部署docker,ubuntu下载最新的docker

1.#如果Ubuntu自带的Docker版本太低&#xff0c;我们需要卸载旧版本并安装新的 sudo apt-get remove docker docker-engine docker.io containerd runc2.# 备份原有软件源 sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak3.选择合适的镜像源 # 或者使用清华大学sudo…

利用WPF绘制轮廓并保存为图片

1.前言 WPF作为显示工具也挺好用&#xff0c;用C#开发应用软件会比较省力&#xff0c;当然也有其缺点&#xff0c;如在对效率要求较高的情况下有性能问题&#xff0c;本文记录用WPF绘制轮廓并保存为图片相关内容。 显示效果也还不错&#xff0c;满足调试使用了&#xf…

变电站缺陷数据集8307张,带xml标注和txt标注,可以直接用于yolo训练

变电站缺陷数据集8307张&#xff0c; 带xml标注和txt标注&#xff0c;可以直接用于yolo训练&#xff0c;赠附五个脚本 变电站缺陷数据集 数据集概述 变电站缺陷数据集是一个专门针对变电站设备和环境缺陷检测的图像数据集。该数据集包含了8307张经过标注的图像&#xff0c;旨…

Maven和Springboot初识

&#xff08;一&#xff09;Maven Maven是一个项目管理工具&#xff0c;通过一小段描述信息来管理项目的构建&#xff0c;报告和文档的项目管理工具 &#xff08;可以通过pom.xml文件的配置来获取jar包&#xff0c;而不用手动添加&#xff09; Maven可以提高我们的开发效率减少…

Mistral AI 又又又开源了闭源企业级模型——Mistral-Small-Instruct-2409

就在不久前&#xff0c;Mistral 公司在开源了 Pixtral 12B 视觉多模态大模型之后&#xff0c;又开源了自家的企业级小型模型 Mistral-Small-Instruct-2409 &#xff08;22B&#xff09;&#xff0c;这是 Mistral AI 最新的企业级小型模型&#xff0c;是 Mistral Small v24.02 的…

C++源代码封装成dll动态链接库,并在WPF项目中使用的步骤说明

文章目录 1. 创建并生成C的DLL&#xff08;C动态链接库&#xff09;&#xff08;1&#xff09;新建项目-->开发语言选定C&#xff0c;在搜索栏搜索“动态链接库”-->配置项目名称和路径-->添加类&#xff0c;此处命名为My_C_Class&#xff08;2)实现类的功能&#xff…