node+koa+mysql(一)

最近学了 Node.js 相关课程,来总结记录一波~

Koa

基本概念

Koa 是一个基于 Node.jsWeb 框架,由 Express.js 的原作者设计和开发,旨在提供一种更加简洁、灵活的方式来构建 Web 应用。Koa 采用了异步、中间件和生成器等概念,让开发者能够更轻松地处理请求和响应、控制流程以及处理异步操作。

实例

我们先来新建一个文件夹,然后在该文件夹下执行以下命令:

csharp 复制代码
// 先初始化仓库
npm init
// 然后安装koa,本文使用的koa版本为2.15.0
npm install koa

新建一个 app.js 文件,先来学习一下必修的 "Hello World" 应用。

javascript 复制代码
// 引入Koa.js
const Koa = require("koa")
// 创建一个新的Koa实例
const app = new Koa()
// 定义一个中间件函数
app.use(async ctx => {
    // 设置响应体的内容
    ctx.body = 'Hello World'
})
// 告诉 Koa 应用在端口 3000 上监听传入的 HTTP 请求,要确保3000端口号没有被其它的应用占用,否则会报错。
app.listen(3000)

终端运行app.js

复制代码
node app.js

然后打开我们的浏览器,输入http://localhost:3000/,可以看到屏幕上显示了 "Hello World"。

总的来说,这段代码创建了一个在端口 3000 上监听的 Web 服务器,当收到请求时,服务器会返回 "Hello World" 的响应。

中间件

上面的代码注释中,我们有看到一个概念"中间件",什么是中间件呢?

中间件函数是一个异步函数,它的主要作用是在请求和响应对象上添加一些行为,例如设置响应体的内容、处理请求数据等,在 Koa 中,多个中间件可以串联起来形成一个处理管道,每个中间件函数可以修改请求和响应参数,并将它们传递给下一个中间件函数。

中间件函数接收两个参数,第一个参数为上下文(context),包含了请求和响应的信息。第二个参数是一个 next 函数,调用它可以传递控制权给下一个中间件。

中间件的执行顺序遵从洋葱模型,以next()函数作为分隔点,洋葱模型的执行过程分为两部分:首先从外向内执行请求相关的逻辑,然后从内向外执行响应相关的逻辑。

我们来看下实际例子理解下,修改app.js文件:

javascript 复制代码
const Koa = require('koa');
const app = new Koa();

// 中间件1
app.use(async (ctx, next) => {
  console.log("中间件1 next之前");
  // await next();
  console.log("中间件1 next之后");
});

// 中间件2
app.use(async (ctx, next) => {
  console.log("中间件2 next之前");
  // await next();
  console.log("中间件2 next之后");
});

// 中间件3
app.use(async (ctx, next) => {
  console.log("中间件3 next之前");
  // await next();
  console.log("中间件3 next之后");
});

app.listen(3000);

我们再次打开浏览器进行访问的时候,发现我们的修改是没有生效的,因为我们没有重新运行 app.js 文件,每次改动都需要重新运行才会生效,这样着实有点麻烦,所有我们先来全局安装下 nodemon,它可以监听 node.js 源代码的任何变化并自动重启我们的服务。

复制代码
npm install -g nodemon

安装完成之后,可以终端输入以下命令运行我们的文件:

复制代码
nodemon app.js

之后我们对 app.js 进行任何修改都不需要重新运行了。nodemon 也可以结合我们的编辑器,打开 vscode,点击左侧菜单栏的"运行和调试":

我们的项目根目录下就会生成一个 /.vscode/launch.json 文件,打开该文件,点击右下角的"添加配置":

保存之后,再次点击左侧菜单栏的"运行和调试":

点击小三角运行我们的文件,然后打开浏览器,输入http://localhost:3000/进行访问。终端的输出如下:

lua 复制代码
中间件1 next之前
中间件1 next之后

可以看到我们在没有调用 next 函数的时候,只有第一个中间件函数被执行了,后面的都不执行。再把 await next() 前的注释去掉,重新访问页面,终端的输出如下:

lua 复制代码
中间件1 next之前
中间件2 next之前
中间件3 next之前
中间件3 next之后
中间件2 next之后
中间件1 next之后

现在再去看下之前的概念,是不是就很清晰了呢~

路由

我们的 API 都有不一样的路径,Koa 是怎么获取 API 的路径并执行相应业务的呢?这就需要通过路由来实现,路由可以根据不同的 URL 路径和 HTTP 请求方法,将请求分发到不同的处理函数,从而实现不同的功能。在 Koa 中,路由的实现需要使用第三方路由中间件,本文使用的是 koa-router。使用步骤如下:

1、安装 koa-router

复制代码
npm install koa-router

2、修改 app.js 文件:

javascript 复制代码
const Koa = require("koa");
// 引入koa-router
const Router = require("koa-router")

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

// 定义路由,定义一个GET请求的根路径"/"的路由
router.get('/', (ctx, next) => {
    ctx.body = "Hello World"
})

// 定义路由,定义一个GET请求的"/home"路径的路由
router.get('/home', (ctx, next) => {
    ctx.body = "home"
})

// 将router对象挂载到koa的app对象上
app.use(router.routes())

app.listen(3000);

浏览器中访问http://localhost:3000/,页面会显示"Hello World"。访问http://localhost:3000/home,页面会显示"home"。

如果把所有的路由都统一写在 app.js 中的话,就会使得我们的路由混乱难以维护。实际开发中,我们需要根据实际项目需求和业务模块将路由进行不同的划分。 每个模块的路由可以集中管理,方便开发和维护。一些常见的划分方式如下:

  • 根据业务模块划分:可以根据不同的业务模块来划分路由,例如用户模块、商品模块、订单模块等。
  • 根据功能划分:可以根据不同的功能来划分路由,例如登录、注册、获取用户信息、获取商品信息等。
  • 根据请求类型划分:可以根据不同的请求类型来划分路由,例如GET请求、POST请求、PUT请求、DELETE请求等。
  • 根据资源划分:可以根据不同的资源来划分路由,例如用户资源、商品资源、订单资源等。

本文要实现一个书籍列表,点进去之后可以看书籍介绍,书籍评论,以及对书籍进行收藏。所以将路由划分为四大块:用户(user)、书籍(book)、评论(comment)、我的收藏(favor)。

项目根目录下新建文件夹 /app/api/v1v1 文件夹标识的是版本,若后续需要对项目进行整体升级,则新的 API 就都放到 v2 文件夹中。然后新建以下四个文件:

/app/api/v1/user

ini 复制代码
const Router = require("koa-router");

const router = new Router({
    prefix: "/v1/user",
});

router.get('/', (ctx, next) => {
    ctx.body = "用户"
})

module.exports = router

/app/api/v1/book

ini 复制代码
const Router = require("koa-router");

const router = new Router({
    prefix: "/v1/book",
});

router.get('/list', (ctx, next) => {
    ctx.body = "书籍列表"
})

module.exports = router

/app/api/v1/comment

ini 复制代码
const Router = require("koa-router");

const router = new Router({
    prefix: "/v1/comment",
});

router.get('/list', (ctx, next) => {
    ctx.body = "评论列表"
})

module.exports = router

/app/api/v1/favor

ini 复制代码
const Router = require("koa-router");

const router = new Router({
    prefix: "/v1/favor",
});

router.get('/list', (ctx, next) => {
    ctx.body = "收藏列表"
})

module.exports = router

最后我们需要这些路由注册为 Koa 的中间件, 修改 app.js 文件:

php 复制代码
const Koa = require("koa");
const userRouter = require("./app/api/v1/user")
const bookRouter = require("./app/api/v1/book")
const commontRouter = require("./app/api/v1/comment")
const favorRouter = require("./app/api/v1/favor")

const app = new Koa();

app.use(userRouter.routes())
app.use(bookRouter.routes())
app.use(commontRouter.routes())
app.use(favorRouter.routes())

app.listen(3000);

浏览器输入相应路由就可以看到相应的返回。

复杂的项目中,路由肯定不止这么几个,如果需要一个个引入并注册的话那就太繁琐了,接下来我们来实现下路由的自动注册。

app.js 文件中不适合放太多的逻辑,所以我们新建一个文件用来进行初始化相关的操作。

根目录下新建文件 /code/init.js,我们需要借助一个第三方模块:require-directory, 它可以递归遍历指定的目录。

安装 require-directory

go 复制代码
npm install `require-directory`

/code/init.js

javascript 复制代码
const requireDirectory = require("require-directory");
const Router = require("koa-router");

class InitManager {
    static initCore(app){
        InitManager.app = app
        InitManager.initLoadRouters()
    }

    static initLoadRouters(){
        const api = `${process.cwd()}/app/api`

        requireDirectory(module, api, {visit: whenLoadModule})

        function whenLoadModule(obj){
            // 判断当前模块是否是路由模块,是才注册为中间件
            if(obj instanceof Router){
                InitManager.app.use(obj.routes())
            }
        }
    }
}

module.exports = InitManager;

require-directory 接收三个参数:

1、固定参数 modulemodule 是指当前模块的引用,在 Node.js 中,每个模块都有一个指向其本身的引用,可以通过 module 变量来获取,require-directory 通过该参数知道从哪个目录开始加载路由文件。

2、目录路径:指定 require-directory 自动加载的路径。

3、options 对象: 这是一个可选参数,可以使用它定义 require-directory 的行为。上面的代码中,visit 函数将在每个模块被加载时调用。

最后修改 app.js 文件:

ini 复制代码
const Koa = require("koa");
const InitManager = require("./core/init")

const app = new Koa();

InitManager.initCore(app)

app.listen(3000);

改造完成!之后路由文件有增加的时候就不需要我们手动引入注册了。

到这里相信大家对 Koa 的基本使用已经了解了,下一篇我们先来连接 MySQL

相关推荐
万少2 小时前
鸿蒙创新赛 HarmonyOS 6.0.0(20) 关键特性汇总
前端
桦说编程2 小时前
爆赞!完全认同!《软件设计的哲学》这本书深得我心
后端
thinktik2 小时前
还在手把手教AI写代码么? 让你的AWS Kiro AI IDE直接读飞书需求文档给你打工吧!
后端·serverless·aws
还有多远.2 小时前
jsBridge接入流程
前端·javascript·vue.js·react.js
蝶恋舞者2 小时前
web 网页数据传输处理过程
前端
非凡ghost3 小时前
FxSound:提升音频体验,让音乐更动听
前端·学习·音视频·生活·软件需求
吃饭最爱3 小时前
html的基础知识
前端·html
我没想到原来他们都是一堆坏人3 小时前
(未完待续...)如何编写一个用于构建python web项目镜像的dockerfile文件
java·前端·python
前端Hardy3 小时前
HTML&CSS:有趣的漂流瓶
前端·javascript·css