Koa入门(一)—— Koa项目基础框架搭建

Koa项目基础框架搭建

  • 项目初始化
  • 项目自动重启
  • 配置ES6语法
  • 基本目录搭建
    • 配置env信息
    • 自动加载路由
    • 统一异常处理
      • 自定义异常
      • 异常处理中间件
    • 中间件配置
    • 目录别名配置

项目初始化

mkdir koa-demo
yarn init
yarn add koa koa-router

这里使用 yarn 包管理器进行项目依赖管理。

// index.js
const app = require('./app');

const port = 4000;

app.listen(port, () => {
  console.log(`Koa项目启动成功:http://localhost:${port}`);
});
// app.js
const Koa = require('koa');
const Router = require('koa-router');

const app = new Koa();

const router = new Router();

router.get('/', async (ctx, next) => {
  ctx.body = '

这是主页

'
; }); router.get('/hello/:name', async (ctx, next) => { ctx.body = `

你好,${ctx.params.name}

`
; }); app.use(router.routes()); module.exports = app;
// package.json
{
  "name": "koa-demo",
  "version": "1.0.0",
  "description": "koa项目基本目录结构",
  "main": "index.js",
  "repository": "https://gitee.com/ljw_full/koa-demo.git",
  "author": "ljw",
  "license": "MIT",
  "scripts": {
    "dev": "node index.js"
  },
  "dependencies": {
    "koa": "^2.11.0",
    "koa-router": "^8.0.8"
  }
}

这就是一个最简单的Koa项目了,使用yarn dev 后就会在4000端口启动一个WEB服务:

Koa入门(一)—— Koa项目基础框架搭建_第1张图片

项目自动重启

在开发时,经常需要改代码看效果,但是每次手动关闭项目,启动项目很麻烦,所以就用到 nodemon 这个自动重启工具,每次修改完代码保存后,就可以自动重启整个项目查看效果了。

npm i nodemon -g 这里我使用全局安装 nodmeon ,因为我只配置了 npm 的path,所以这里就用 npm 安装 nodemon

修改 package.jsonscript.dev 脚本为:nodemon index.js

配置ES6语法

在这里你使用 import 会发现报错 SyntaxError: Unexpected identifier(Node支持大部分ES6语法,不过这个import 关键字却没有)

这里需要使用 babel 来进行编译才可以执行:

yarn add babel-cli babel-preset-es2015 -D

然后再根目录添加一个新文件 .babelrc

{
  "presets": ["es2015"]
}

启动脚本配置如下:

{
  "scripts": {
    "dev": "nodemon index.js --exec babel-node",
    "prod": "babel-node index.js"
  },
}

基本目录搭建

一个项目的开发都有一套良好的目录结构,什么代码放哪个目录下。

.
├── app.js
├── index.js                   # 项目启动入口
├── package.json
├── src
    ├── main                   # 项目代码
    │   ├── common             # 通用模块
    │   ├── config             # 配置
    │   ├── controller         # 接口
    │   ├── middleware         # 中间件
    │   ├── model              # 模型层
    │   └── service            # 服务层
    │   └── util               # 工具层
    └── test                   # 测试目录

这里的 app.js 和 index.js 分开来写是为了方便测试接口

配置env信息

通常一些配置都会分为开发环境,测试环境,生成环境,最典型的就是数据库连接信息了。

这里使用 dotenv 来配置 env:yarn add docenv

然后创建一个 .env 文件:

NODE_ENV=dev

PORT=4000

index.js 中最上方添加一行代码:

import 'dotenv/config';
import Koa from 'koa';
import router from './src/main/router';

const app = new Koa();

// 加载所有路由
router(app);

export default app;

一般 .env 文件不会进入git版本库,我通常都会放一个 .env.example 里面写着样例配置,然后根据这个 .env.example 复制出 .env 文件编写真正的信息。

你的一些私密信息都可以写在 .env 文件里,例如你的数据库连接信息,一些第三方的私钥密钥信息等。

自动加载路由

开发一个项目,通常都会有很多的接口,所以不可能把接口都写在app.js里面,我这里把接口都放到了src/main/controller 目录下,例如现在我编写了一个测试模块:

// src/main/api/TestController.js
import Router from 'koa-router';

let testRouter = new Router({
  prefix: '/test'
});

testRouter.get('/', async ctx => {
  ctx.body = '

测试主页

'
; }); testRouter.get('/hello/:name', async ctx => { ctx.body = `

你好啊,${ctx.params.name}

`
; }); export default testRouter;

这里使用一个require-directory库,他可以很方便的递归检索目录下的文件:yarn add require-directory

// src/main/router.js
import requireDirectory from 'require-directory';
import Router from 'koa-router';

export default app => {
  requireDirectory(module, './controller', {
    visit: (obj) => {
      if (obj.default instanceof Router) {
        app.use(obj.default.routes());
      }
    }
  })
}

这里遍历递归 src/main/controller 目录,visit 接受一个函数,obj 就是那个文件export的对象,如果这个 obj 是 Router 实例,就加载到路由,这样子,你在 src/main/controller 下编写多少个文件都可以自动加载。

最后在 app.js 中引入这个 router.js 文件:

import Koa from 'koa';
import router from './src/main/router';

const app = new Koa();

// 加载所有路由
router(app);

export default app;

统一异常处理

自定义异常

export const COMMON_ERROR_CODE = 500;
export const PARAM_ERROR_CODE = 501;


/**
 * 通用异常
 */
export class CommonError extends Error {
  constructor(code = COMMON_ERROR_CODE, msg = '服务器异常') {
    super();
    this.code = code;
    this.msg = msg;
  }
}


/**
 * 参数异常
 */
export class ParamError extends CommonError {
  constructor(msg = '参数异常') {
    super(PARAM_ERROR_CODE, msg);
  }
}

异常处理中间件

// src/main/middleware/globalError.js
import { CommonError } from '../common/CommonError';

export default () => {
  return async (ctx, next) => {
    try {
      await next();
    } catch (err) {
      if (err instanceof CommonError) {
        ctx.body = err;
      } else {
        ctx.body = new CommonError();
      }
    }
  };
};

不过这里的 err instanceof CommonError 可能一直都是 false ,需要添加一个 babel 插件:yarn add babel-plugin-transform-builtin-extend -D

.babelrc 中配置一下插件:

{
  "presets": ["es2015"],
  "plugins": [
    [
      "babel-plugin-transform-builtin-extend",
      { "globals": ["Error", "Array"] }
    ]
  ]
}

最后在 app.js 中引入中间件:

import Koa from 'koa';
import router from './src/main/router';
import globalError from './src/main/middleware/globalError';

const app = new Koa();

// 全局异常处理
app.use(globalError());

// 加载所有路由
router(app);

export default app;

使用:

import Router from 'koa-router';
import { ParamError, CommonError } from '../common/CommonError';

let testRouter = new Router({
  prefix: '/test'
});

testRouter.get('/exception', async ctx => {
  // ctx.body = ctx._matchedRouteName.msg;
  throw new ParamError('缺少参数');
});

export default testRouter;

中间件配置

中间件会统一放到 src/main/middleware 目录下,如果中间件过多在 app.js 中引入也是比较麻烦,所以这里可以写个中间件配置。

配置文件在 src/main/config 目录下:

// src/main/config/index.js
export default {
  middlewares: [
    'globalError'
  ]
};

这里的 middlewares 是个数组,存放的是 middleware 目录下的中间件的文件名,带不带 .js 都可以。

然后在 middleware.js 中处理中间件:

// src/main/middleware.js
import config from './config';

export default (app) => {
  if (config.middlewares) {
    let middleware;
    config.middlewares.forEach(item => {
      middleware = require(`./middleware/${item}`).default;
      app.use(middleware());
    });
  }
};

app.js 中处理 middleware.js

import Koa from 'koa';
import router from './src/main/router';
import middleware from './src/main/middleware';

const app = new Koa();

// 中间件处理
middleware(app);

// 加载所有路由
router(app);

export default app;

添加一个中间件,在 config/index.jsmiddlewares 数组中添加一下中间件文件名即可。

目录别名配置

如果的你的目录层次够深,可能会遇到 import '../../../src/main/config'; 的代码,此时我们可以使用 @main 来代替 src/main 目录。

安装:yarn add module-alias

package.json 中添加:

{
  "_moduleAliases": {
    "@main": "./src/main"
  }
}

app.js 中引入一个依赖:

import 'module-alias/register';
import Koa from 'koa';
import router from '@main/router.js';
import middleware from '@main/middleware';

const app = new Koa();

// 中间件处理
middleware(app);

// 加载所有路由
router(app);

export default app;

接下来下面的所有地方都可以使用 @main 这个目录别名了。

但是此时 VScode 的路径提示可能会没有了,需要在 根目录下添加一个 jsconfig.json 文件:

{
  "compilerOptions": {
      "target": "ES6",
      "module": "commonjs",
      "allowSyntheticDefaultImports": true,
      "baseUrl": "./",
      "paths": {
        "@main/*": ["src/main/*"]
      }
  },
  "exclude": [
      "node_modules"
  ]
}

点击查看源码

相关文章:

  • Koa入门(二)—— 使用Sequelize连接Mysql
  • Koa入门(三)—— Koa项目自动化测试
  • Koa入门(四)—— Koa使用JWT做权限认证
  • Koa入门(五)—— 使用log4j记录日志

你可能感兴趣的:(koa)