node+koa+mysql(一)

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

Koa

基本概念

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

实例

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

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

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

// 引入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()函数作为分隔点,洋葱模型的执行过程分为两部分:首先从外向内执行请求相关的逻辑,然后从内向外执行响应相关的逻辑。

node+koa+mysql(一)

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

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,点击左侧菜单栏的“运行和调试”:

node+koa+mysql(一)

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

node+koa+mysql(一)

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

node+koa+mysql(一)

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

中间件1 next之前
中间件1 next之后

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

中间件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 文件:

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

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

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

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

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 文件:

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

npm install `require-directory`

/code/init.js

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 文件:

const Koa = require("koa");
const InitManager = require("./core/init")

const app = new Koa();

InitManager.initCore(app)

app.listen(3000);

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

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

原文链接:https://juejin.cn/post/7329144189002006568 作者:SummerStar

(0)
上一篇 2024年1月29日 下午4:47
下一篇 2024年1月29日 下午4:57

相关推荐

发表回复

登录后才能评论