Giter Club home page Giter Club logo

koa-app's Introduction

koa-app koa 实战总结

1. 初始化项目 启动服务

mkdir koa-app
npm init -y
git init

yarn add koa -S
yarn add nodemon -D

mkdir app
cd app
touch index.js
vi index.js

cd.. to folder koa-app

vi package.json
add "scripts": "start": "nodemon app/index.js",

# 启动项目
yarn start ==> server on localhost:9000

2. 提交

2.1 提交规范 commitizen

yarn add commitizen -D

add "scripts": "commit": "git add . && git-cz"

add "config": { "commitizen": { "path": "node_modules/cz-conventional-changelog" }}

2.2 提交到 github & gitee

前提是:两个账户已分别绑定 git 权限

git remote add github [email protected]:xn213/koa-app.git
git remote add gitee [email protected]:xn213/koa-app.git

yarn commit

# 分别提交
git push github
git push gitee

升级省事: 同时提交到 github 和 gitee

修改 .git/config

[remote "origin"]
	url = [email protected]:xn213/koa-app.git
	url = [email protected]:xn213/koa-app.git
	fetch = +refs/heads/*:refs/remotes/origin/*

这时第一次提交到 gitee, alias: gp == git push 会提示如下图,

2021_06_06_git-push-to-both-github-gitee

由于上面分别提交到 github 和 gitee, 设置了 git remote gitee..., 要使用如下命令提交

git push --set-upstream origin master

此命令会在 .git/config 中添加如下字段

[branch "master"]
	remote = origin
	merge = refs/heads/master

3. 改造路由

3.1 抽离路由模块

yarn add koa-router -S

cd app
mkdir router
touch index.js
touch routes.js

4. 参数解析,抽离中间件

4.1 koa-compose 简化中间件引用

yarn add koa-compose koa-bodyparser -S
# 插件 koa-compose 简化引用中间件的写法。
# 插件 koa-bodyparser 处理 post 请求体中的参数
// app/index.js
const compose = require('koa-compose')
const MD = require('./middlewares/')

const app = new Koa()

app.use(compose(MD))
// controllers/test.js
ctx.body = ctx.request.body

这里 post 请求 拿不到 body 的参数,找轮子>插件

4.2 koa-bodyparser 处理 post 请求参数

// >app
mkdir middlewares
touch index.js

# 注意: koa-bodyparser 处理需放在路由前面

koa-middleware-bodyparser

post-body

4.3 formidable 处理 上传文件

koa-bodyparser 插件只能解析 4 种数据 [ 'json', 'form', 'text', 'xml' ],当上传文件的时候,是获取不到文件的. 这里借助插件 formidable 文档

yarn add formidable -S
// middlewares/formidable.js
const Formidable = require('formidable')

const { tempFilePath } = require('../config')

module.exports = () => {
  return async function (ctx, next) {
    const form = new Formidable({
      multiples: true,
      // 上传的临时文件保存路径 抽离到 config/base 一些配置
      // uploadDir: `${process.cwd()}/${tempFilePath}`
      uploadDir: tempFilePath,
    })

    await new Promise((reslove, reject) => {
      form.parse(ctx.req, (err, fields, files) => {
        if (err) {
          reject(err)
        } else {
          // 暂未设置请求头 忽略 请求中添加 二进制 content-type
          ctx.request.body = fields
          ctx.request.files = files
          reslove()
        }
      })
    })

    await next()
  }
}
// middlewares/index.js 中引入 注册 暴露出去
const formidable = require('./formidable')
const mdFormidable = formidable()
module.exports = [mdFormidable, mdKoaBody, mdRoute, mdRouterAllowed]

注: Koa Docs: content-type

koa9000-upload-file-content-type--application--octet-stream

koa-9000-upload-file-temp-folder

另: 抽离配置文件,添加配置文件目录: app/config

// config/index.js
const base = require('./base')
const dev = require('./dev')
const pre = require('./pre')
const pro = require('./pro')

const env = process.env.NODE_ENV || 'dev'

const configMap = {
  dev,
  pre,
  pro,
}

module.exports = Object.assign(base, configMap[env])

5. 工具函数和常量配置抽离 挂载到上下文

编写工具函数 app/utils/index.js & test.js

cd app
mkdir utils
cd utils
touch index.js
vi index.js i 编辑输入: :wq 保存退出
// utils/index.js
const testUtils = require('./test')

module.exports = {
  testUtils,
}
touch test.js
vi test.js  i编辑输入
// utils/test.js
const test = 'test utils string'

module.exports = testUtils = () => {
  return test
}

挂载到 App context 上下文

// app/index.js
...
const config = require('./config')
const utils = require('./utils')

app.context.utils = config
app.context.utils = utils
...

6. 统一返回格式 & 错误处理

6.1 统一 成功 or 失败 返回格式

  1. 成功
// app/middlewares/response.js
const response = () => {
  return async (ctx, next) => {
    ctx.res.fail = ({ code, data, msg }) => {
      ctx.body = {
        code,
        data,
        msg,
      }
    }
    ctx.res.success = (msg) => {
      ctx.body = {
        code: 0,
        data,
        msg: msg || 'success',
      }
    }
    await next()
  }
}
module.exports = response
  1. 失败
// app/middlewares/error.js
const error = () => {
  return async (ctx, next) => {
    try {
      await next()
      if (ctx.status === 200) {
        ctx.res.success()
      }
    } catch (err) {
      if (err.code) {
        ctx.res.fail({ code: err.code, msg: err.message })
      } else {
        // 程序运行时错误
        ctx.app.emit('error', err, ctx)
      }
    }
  }
}
module.exports = error
  1. middlewares/index.js 中引入
const response = require('./response')
const error = require('./error')

const mdResHandler = response()
const mdErrHandler = error()

module.exports = [mdFormidable, mdKoaBody, mdResHandler, mdErrHandler, mdRoute, mdRouterAllowed]

6.2 错误处理

  1. 程序运行时错误使用 koa 的错误处理事件,需要在 app/index.js 配置

所有的返回值是在 middlewares/error.js 里拦截了一下,如果状态码是 200,用成功的工具函数包装返回,如果不是则又分为两种情况:一种是我们自己抛出的,包含业务错误码的情况(这种情况我们用失败的工具函数包装返回);另一种是程序运行时报的错,这个往往是我们代码写的有问题(这种情况我们触发 koa 的错误处理事件去处理),针对失败的第二种情况,我们还需要修改启动文件 app/index.js,添加如下代码:

// 程序本身错误
app.on('error' (err, ctx) => {
  if(ctx) {
    ctx.body = {
      code: 9000,
      msg: `程序运行时错误: ${err.message}`
    }
  }
})
  1. 测试一下: 在 controllers/test.js 添加如下代码:

2.1. 成功

// controllers/test.js
const getList = async () => {
  ctx.body = '返回结果'
}

请求接口, 返回值如下,我们定义的 controller 成功返回

koa-成功返回结果-controller-拦截到

2.2. 业务抛出错误

// controllers/test.js
const getList = async (ctx) => {
  const data = ''
  // 业务中抛出失败
  ctx.utils.assert(data, ctx.utils.throwError(10001, '验证码失效'))
  ctx.body = '返回结果'
}

koa-业务中抛出错误10001

2.3. 程序本身报错

这时添加一行 a = b, 这里 b 未定义,则为程序本身错误, 触发 koa error 事件

const getList = async (ctx) => {
  const a = b
  ctx.body = '返回结果'
}

koa

7. 跨域处理 @koa/cors

直接用插件 @koa/cors npm/@koa/cors

app/middlewares/index.js 中引入,实例化,导出

// middlewares/index.js 跨域处理
const cors = require('@koa/cors')
const mdCors = cors({
  origin: '*',
  credentials: true,
  allowMethods: ['GET', 'HEAD', 'PUT', 'POST', 'DELETE', 'PATCH'],
})

module.exports = [
  mdFormidable,
  mdKoaBody,
  mdCors,
  mdResHandler,
  mdErrorHandler,
  mdRoute,
  mdRouterAllowed,
]

8. 添加日志 log4js

插件:log4js

// middlewares/log.js
const log4js = require('log4js')
const { flag, level, outDir } = require('../config').logConfig

log4js.configure({
  appenders: {
    cheese: {
      type: 'file',
      filename: `${outDir}/receive.log`,
    },
  },
  categories: {
    default: {
      appenders: ['cheese'],
      level: 'info',
    },
  },
  pm2: true,
})

const logger = log4js.getLogger()
logger.level = level

module.exports = () => {
  return async (ctx, next) => {
    const { method, path, origin, query, body, headers, ip } = ctx.request
    const data = {
      method,
      path,
      origin,
      query,
      body,
      ip,
      headers,
    }
    await next()
    if (flag) {
      const { status, params } = ctx
      data.status = status
      data.params = params
      data.result = ctx.body || 'no content'
      if (ctx.body.code !== 0) {
        logger.error(JSON.stringify(data))
      } else {
        logger.info(JSON.stringify(data))
      }
    }
  }
}

app/middlewares/index.js 引入/注册/配置

const log = require('./log')
const mdLogger = log()

module.exports = [
  mdFormidable,
  mdKoaBody,
  mdCors,
  mdLogger,
  mdResHandler,
  mdErrHandler,
  mdRoute,
  mdRouterAllowed
]

koa-app's People

Contributors

xn213 avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.