应用nodejs注册接口逻辑解决会比较复杂,间接通过express或者koa可能简化开发流程,这里记录用koa来搭建nodejs我的项目并注册接口,对koa不太熟悉的话能够参考这一篇。让nodejs开启服务更简略--koa篇

我的项目构造

我的项目整体构造如下,将不同性能的文件按模块划分,使得代码逻辑更为清晰

node_modules      // 装置的包src                     // 本人编码的局部    app               // 注册的app    constants        // 定义常量    controller       // 注册接口所应用到的办法    middleware     // 解决数据的中间件    router            // 路由    service            // 定义sql语句    utils               // 解决数据的办法    main.js           // 入口.env                    // 放到环境变量的配置文件 package-lock.json  // 包的依赖关系package.json        // 须要装置哪些包

注册app

koa中所有的操作都须要通过注册的这个app对象来实现,先在 app/index.js 中注册并导出

const Koa = require('koa')const app = new Koa()    module.exports = app

http开启服务

我的项目根目录建设 main.js文件,引入app对象,开启http服务

const app = require('./app')const { APP_PORT } = require('./app/config')app.listen(APP_PORT, ()=>{    console.log('开启服务啦')})

账号密码、端口号等信息间接写在文件中是不平安的,上传或共享我的项目的时候容易泄露,所以保留到不影响我的项目的的文件当中,根目录中新增 .env 文件,应用 dotenv 将 .env 文件中的配置项注册到环境变量中

APP_PORT=8000

app文件夹中新增config.js文件用于保留配置信息,避免随便更改

const dotenv = require('dotenv')dotenv.config();module.exports = {    APP_PORT} = process.env

启动 main.js就曾经能够监听8000端口了,因为没有对申请做出响应,所以此时拜访8000,只能返回 Not Find

注册路由

一组路由就是一组映射关系,定义门路与处理函数,如下演示注册的接口逻辑,中间件用来判断数据的正确性,管制层的函数用来进行响应

const Router = require('koa-router')const RegisterRouter = new Router({ prefix: '/register' })const { register } = require('../controller/register.controller')const { verifyUser, encryptionPwd } = require('../middleware/register.middleware')RegisterRouter.post('/', verifyUser, encryptionPwd, register)module.exports = RegisterRouter

中间件

判断是否传入了用户名和明码以及是否已注册,对传入的隐衷数据进行加密

const crypto = require('crypto')const { hasUser } = require('../service/register.service')const { USER_ALREADY_EXISTS,  NAME_OR_PASSWORD_REQUIRED } = require('../constants/error-types')  class RegisterMiddleWare {  async verifyUser(ctx, next) {    const { name, password } = ctx.request.body    if (!name || !password) {      const error = new Error(NAME_OR_PASSWORD_REQUIRED)      return ctx.app.emit('error', error, ctx)    }    let users = await hasUser(name)    if (users) {      const error = new Error(USER_ALREADY_EXISTS)      return ctx.app.emit('error', error, ctx)    }    await next()  }    async encryptionPwd(ctx, next) {    const { password } = ctx.request.body    const md5 = crypto.createHash('md5')    const pwd = md5.update(password).digest('hex')    ctx.request.body.password = pwd    await next()  }}module.exports = new RegisterMiddleWare()

与数据库建设连贯

创立表构造

CREATE TABLE IF NOT EXISTS `user`(    id INT PRIMARY KEY AUTO_INCREMENT,    name varchar(50) NOT NULL UNIQUE,    password varchar(200) NOT NULL,    createAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,    updateAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP);

service/register.service.js 中定义插入数据库的办法

const connection = require('../app/database')class RegisterService {  async hasUser(name) {    const statement = `SELECT * FROM user WHERE name = ?`    try {      const [result] = await connection.execute(statement, [name])      return result.length    } catch (error) {      console.log('LoginService-hasUser', error)    }  }    async insertUser(name, password) {    const statement = `INSERT INTO user(name, password) VALUES(?,?)`    try {      const [result] = await connection.execute(statement, [name, password])      return result    } catch (error) {      console.log('LoginService-insertUser', error)    }  }}module.exports = new RegisterService()

很多中央都须要用到与数据库的连贯,所以在 app/databse.js 中对立建设连接池

const mysql = require('mysql2')const { MYSQL_HOST,  MYSQL_PORT,  MYSQL_DATABASE,  MYSQL_USER,  MYSQL_PASSWORD, } = require('./config')const connection = mysql.createPool({  database: MYSQL_DATABASE,  host: MYSQL_HOST,  port: MYSQL_PORT,  user: MYSQL_USER,  password: MYSQL_PASSWORD})connection.getConnection((error, conn)=>{  conn.connect((err)=>{    console.log(error, err)  })})module.exports = connection.promise()

数据库的账号密码间接硬编码写在代码中会存在问题,同样的写到 .env 文件中,通过config.js 导出

// .envMYSQL_HOST=localhostMYSQL_PORT=3306MYSQL_DATABASE=mallMYSQL_USER=rootMYSQL_PASSWORD=123456APP_PORT=8000
// config.jsconst dotenv = require('dotenv')dotenv.config()module.exports = {  APP_PORT,  MYSQL_HOST,  MYSQL_PORT,  MYSQL_DATABASE,  MYSQL_USER,  MYSQL_PASSWORD,} = process.env

捕捉谬误

当注册账号时,用户已注册或者明码不符合规范须要返回错误信息,在 constants/error-types 中定义常见的错误信息

const USER_ALREADY_EXISTS = 'user_already_exists'const NAME_OR_PASSWORD_REQUIRED = 'name_or_password_required'module.exports = {  USER_ALREADY_EXISTS,  NAME_OR_PASSWORD_REQUIRED}

app/error-handle.js 中对错误信息进行判断

const {  USER_ALREADY_EXISTS} = require('../constants/error-types')const errorHandle = (error, ctx) => {  let code = 200  let message = ''  switch (error.message) {    case USER_ALREADY_EXISTS:      message = '该用户已存在'      break;  }  ctx.status = code  ctx.body = message}module.exports = errorHandle

app/index.js 引入路由定义的接口,获取post申请传递的参数,并绑定谬误的解决形式

const Koa = require('koa')const app = new Koa()const bodyParser = require('koa-bodyparser')const LoginRouter = require('../router/register.router')const errorHandle = require('./error-handle')app.use(bodyParser())app.use(LoginRouter.routes())app.use(LoginRouter.allowedMethods())app.on('error', errorHandle)module.exports = app

进行响应

在controller/register.controller.js中定义对应的解决办法

const { insertUser } = require('../service/register.service')class RegisterController {  async register(ctx, next) {    const { name, password } = ctx.request.body    const result = await insertUser(name, password)    ctx.body = result  }}module.exports = new RegisterController()

到这里为止,咱们就能够对接口进行拜访啦

以上就是注册一个接口的残缺流程,不同接口可能须要通过不同的中间件去解决,比方登录接口须要验证明码,派发token,其余和用户权限无关的接口须要验证token。

以下还有几篇相干笔记可供参考
jwt实现token鉴权(nodejs koa
如何通过cookie、session鉴权(nodejs/koa)
超具体的mysql总结(DQL)
超具体的mysql总结(基本概念、DDL、DML)
nodejs中如何应用http创立一个服务