• node koa2 初体验


    node koa2 初体验

    时隔 8 个月,经历一番 chuozhe,我又回来了...

    一、koa2 初识

    1. Think

    之前一直用 node 的 express,没有太多框架封装的东西,需要自己手撸 sql 语句,配合 mysql 依赖包进行数据库的连接会话及读写操作。但框架封装的东西少了,自己做的就多了,最近想写一个不知名的 proj,为了进一步减少我写 demo 时的工作量,我决定换个框架试试。

    2. 官网解释

    1. koa 概念

    koa2 是由 Express 原班人马打造的,致力于成为一个更小、更富有表现力、更健壮的 Web 框架。 使用 koa 编写 web 应用,通过组合不同的 generator,可以免除重复繁琐的回调函数嵌套, 并极大地提升错误处理的效率。koa 不在内核方法中绑定任何中间件, 它仅仅提供了一个轻量优雅的函数库,使得编写 Web 应用变得得心应手。

    二、koa2 路由及传值

    1. get 请求及数据获取

    const Koa = require('koa')
    const router = require('koa-router')() //注意:引入的方式
    const app = new Koa()
    
    router.get('/user/find', function (ctx, next) {
      const { username, sex } = ctx.request.query // 从上下文的 request 对象中获取
      ctx.body = '获取所有用户...'
    })
    

    2. post 请求及数据获取

    const Koa = require('koa')
    const router = require('koa-router')() //注意:引入的方式
    const bodyParser = require('koa-bodyparser')
    const app = new Koa()
    
    // 对于POST请求的处理,koa-bodyparser中间件可以把koa2上下文的formData数据解析到ctx.request.body中
    app.use(bodyParser())
    
    router.post('/user/add', function (ctx, next) {
      const { username, sex, age } = ctx.request.body // 从上下文的 request 对象中获取
      ctx.body = '添加用户...'
    })
    

    三、koa2 中间件

    中间件就是匹配路由之前或者匹配路由完成做的一系列的操作,我们就可以把它叫做中间件。

    1. 概念

    在 express 中间件(Middleware) 是一个函数,它可以访问请求对象(request object (req)), 响应对象(response object (res)), 和 web 应用中处理请求-响应循环流程中的中间件,一般被命名为 next 的变量。在 Koa 中中间件和 express 有点类似。

    2. 功能

    • 执行任何代码。
    • 修改请求和响应对象。
    • 终结请求-响应循环。
    • 调用堆栈中的下一个中间件。

    3. 中间件类型

    const Koa = require('koa')
    const app = new Koa()
    
    // 01 应用级中间件
    
    app.use(async (ctx, next) => {
      console.log(`Process ${ctx.request.method} ${ctx.request.url}...`)
      await next()
    })
    
    // 02 路由中间件
    const Router = require('koa-router')
    const router = new Router()
    
    router.get('/', async (ctx, next) => {
      console.log(1)
      ctx.bosy = 'hello koa ~'
    })
    
    // 03 错误处理中间件
    
    app.use(async (ctx, next) => {
      next()
      if (ctx.status === 500) {
        ctx.status = 500
        ctx.body = '服务器出了点小意外~'
      }
    })
    
    // 04 第三方中间件
    const bodyParser = require('koa-bodyparser')
    
    app.use(bodyParser()) // 处理 body 中的参数
    

    4. 执行顺序: 著名的洋葱圈模型。

    // 例如在以下的入口 app.js 中测试以下中间件(已省略无关代码)
    
    ...
    
    const Koa = require("koa")
    const app = new Koa()
    
    // 中间件 01
    app.use(async (ctx, next) => {
      console.log('->>>', 1)
      await next()
      console.log('<<<-', 111)
    })
    
    // 中间件 02
    app.use(async (ctx, next) => {
      console.log('->>>', 2)
      await next()
      console.log('<<<-', 222)
    })
    
    // 中间件 03
    app.use(async (ctx, next) => {
      console.log('->>>', 3)
      await next()
      console.log('<<<-', 333)
    })
    
    app.listen(3000)
    
    ...
    
    // 输出:
    
    ->>> 1
    ->>> 2
    ->>> 3
    <<<- 333
    <<<- 222
    <<<- 111
    

    在以上测试伪代码中,每个中间件都接收了一个 next 参数,在 next 函数运行之前的中间件代码会在一开始就执行,next 函数之后的代码会在内部的中间件全部运行结束之后才执行:

    它首先会走中间件 01,进而打印 ->>> 1,继续走碰到 next,会进入下一个中间件 02,进而打印出 ->>> 2,继续走碰到 next,会进入下一个中间件 03,进而打印出 ->>> 3。依此类推,当走到最后一个中间件后因为没有下一个中间件可执行,从最后一个中间件一层一层返回执行,这里假如 03 是最后一个中间件。继续走,它会打印出 <<<- 333,中间件 03 执行完毕,返回上一个中间件 02,打印出 <<<- 222,中间件 02 执行完毕,返回上一个中间件 01,打印出 <<<- 111,至此所有中间件执行完毕。而这里中间件的执行过程就是 洋葱圈模型

    四、注解式路由工具 koa-swagger-decorator

    koa-swagger-decorator 可以自动生成 swagger json 文档,让我们可以表面使用 MVC 式的注解式路由方式来撸接口及文档。

    1. 需引入 babel 支持

    // npm install --save-dev babel-plugin-transform-decorators-legacy
    // .babelrc
    {
      "presets": [["env", { "targets": { "node": "current" } }]],
      "plugins": ["transform-decorators-legacy"]
    }
    

    2. 写入配置

    // SwaggerRouter.js
    import { SwaggerRouter } from 'koa-swagger-decorator'
    import * as path from 'path'
    
    const router = new SwaggerRouter()
    // swagger 文档地址: http://localhost:3000/api/swagger-html
    router.swagger({
      title: 'A project',
      description: 'Api doc',
      version: '1.0.0',
    })
    
    // 查找对应目录下的controller类: 会将 controller 文件夹下的注解式接口生成一个个的 router
    router.mapDir(path.resolve(__dirname, '../controller/'))
    
    export default router
    
    // app.js
    import router from './router/SwaggerRouter'
    app.use(router.routes())
    

    3. controller 下接口写法

    // UserController.js
    import {
      request,
      summary,
      description, // 接口名称下方的描述信息
      query, // get时参数
      path, // post, put, delete 时地址栏参数
      body, // body中的参数
      tags,
    } from 'koa-swagger-decorator'
    // 引入我的业务操作
    import UserService from '../service/UserService'
    
    const userService = new UserService()
    const tag = tags(['User'])
    
    export default class UserController {
      @request('post', '/user/findById')
      @summary('根据id查询用户数据')
      @tag
      @body({
        id: { type: 'string', required: true },
      })
      async findById(ctx) {
        const bObj = ctx.request.body
        const data = await userService.findById(bObj)
        ctx.rest(data)
      }
    }
    

    五、数据库驱动工具 sequelize

    sequelize 是一个基于 promise 的 Node.js ORM, 目前支持 Postgres, MySQL, MariaDB, SQLite 以及 Microsoft SQL Server. 它具有强大的事务支持, 关联关系, 预读和延迟加载,读取复制等功能。

    1. 安装

    $ npm install --save sequelize
    
    # 必须手动为所选数据库安装驱动程序: 选择以下之一:
    $ npm install --save pg pg-hstore # Postgres
    $ npm install --save mysql2
    $ npm install --save mariadb
    $ npm install --save sqlite3
    $ npm install --save tedious # Microsoft SQL Server
    

    2. 连接数据库

    更多 Sequelize 构造函数参数参考 API

    // sequelizeMysql.js
    import Sequelize from 'sequelize'
    
    const DBConfig = {
      host: 'localhost', // 服务器地址
      port: 3306, // 数据库端口号
      username: 'root', // 数据库用户名
      password: '111111', // 数据库密码
      database: 'demo', // 数据库名称
      prefix: 'api_', // 默认"api_"
    }
    
    export default new Sequelize(
      DBConfig.database,
      DBConfig.username,
      DBConfig.password,
      {
        host: DBConfig.host,
        port: DBConfig.port,
        dialect: 'mysql', // 要连接的数据库:mysql、postgres、sqlite 和 mssql 之一
        pool: {
          max: 50, // 池中最大连接数 默认:5
          min: 0, // 池中最小连接数 默认:0
          idle: 10000, // 连接在被释放之前可以空闲的最长时间(以毫秒为单位)默认:10000
        },
        timezone: '+08:00',
      }
    )
    

    3. 创建表模型

    模型 是 Sequelize 的本质. 模型是代表数据库中表的抽象. 在 Sequelize 中,它是一个 Model 的扩展类

    // UserModel.js
    import Sequelize from 'sequelize'
    import sequelizeMysql from '../utils/sequelizeMysql'
    
    // 创建 model
    const User = sequelizeMysql.define(
      'user',
      {
        id: {
          type: Sequelize.UUID,
          defaultValue: Sequelize.UUIDV1,
          primaryKey: true,
        },
        username: {
          type: Sequelize.STRING(255),
          allowNull: false, // allowNull不设置默认为true
        },
        avatarUrl: {
          type: Sequelize.STRING(255),
          field: 'avatar_url', // 自定义表中的列名称
        },
        createtime: {
          type: Sequelize.STRING(255),
          defaultValue: Date.now(),
        },
        isdelete: {
          type: Sequelize.INTEGER,
          defaultValue: 0,
          allowNull: false,
        },
      },
      {
        // true 表名称和 model 相同: user
        // false 创建表名称会是复数: users
        freezeTableName: true,
        // 是否使用默认的 createdAt updatedAt
        timestamps: false,
      }
    )
    
    // 创建表
    User.sync({ force: false })
    
    export default User
    

    4. 读写操作

    此只简单列举查询添加操作,更多请点击 API 文档 查看模型查询

    // UserDao.js
    import UserModel from '../model/UserModel'
    
    export default class UserDao {
      // 查询用户
      async findById(data) {
        const { id } = data
        return await UserModel.findAll({
          attributes: { exclude: ['isdelete'] }, // exclude: 返回值排除字段
          where: {
            isdelete: 0,
            id,
          },
        })
      }
      // 添加用户
      async add(data) {
        return await UserModel.create(data)
      }
    }
    



    部分代码出自个人 gitee ...

  • 相关阅读:
    关于线程池,那些你还不知道的事
    Java发送邮件
    原来实现项目多环境打包部署是如此的简单
    史上最全的maven的pom.xml文件详解
    Linux系统基础知识整理(一)
    计算机启动过程的简单介绍 计算机启动流程 计算机BIOS作用 POST 开机自检 计算机启动顺序 分区表 操作系统启动
    交换机工作原理、MAC地址表、路由器工作原理详解
    $(function(){})和$(document).ready(function(){}) 的区别
    关于RAM与ROM的区别与理解
    CDN的作用与基本过程
  • 原文地址:https://www.cnblogs.com/Faith-Yin/p/15190487.html
Copyright © 2020-2023  润新知