使用 koa2 搭建中间件

2022-04-25 16:51:03 浏览数 (2)

使用 koa2 搭建中间件

安装依赖

代码语言:javascript复制
{
    "crypto-js": "^3.1.9-1",                   // 加密
    "koa": "^2.8.1",                           // ...
    "koa-bodyparser": "^4.2.1",                // 解析数据
    "koa-router": "^7.4.0",                    // ...
    "koa-sslify": "^4.0.3",                    // 开启ssl
    "koa2-cors": "^2.0.6",                     // 跨域
    "mongodb": "^3.3.1",                       // ...
    "mongoose": "^5.6.11",                     // 更优雅的操作mongodb
    "request": "^2.88.0",                      // ...
    "request-promise": "^4.2.2",               // 发起请求
    "xml2js": "^0.4.23"                        // 微信支付格式化
 }

项目结构

代码语言:javascript复制
|-- ssl/ SSL证书目录
		|-- api.domain.com.crt
    |-- api.domain.com.key

|-- src/ 源代码目录
    |-- controllers/ 控制器
        |-- order.js 订单
        |-- user.js 用户
        |-- ...    
        
    |-- db/ 数据库相关
        |-- connection.js 数据库连接文件
        
    |-- router/ koa路由
        |-- index.js 路由
       
    |-- schemas/ mongoose文档架构
        |-- order.js 订单
        |-- user.js 用户
        |-- ...  
          
   	|-- utils/ 工具类
        |-- encrypt.js 加密
        |-- roles.js 权限
        |-- ... 
    
    |-- app.js 入口文件
    |-- config.js 配置文件
    |-- ...

配置https

在根目录新建 ssl 文件夹,放入证书文件

在 app.js 中引入 koa-sslify 和 fs

代码语言:javascript复制
const sslify = require('koa-sslify').default;
const fs = require('fs');

配置证书目录

代码语言:javascript复制
const httpsOption = {
  key: fs.readFileSync("../ssl/api.domain.com.key"),
  cert: fs.readFileSync("../ssl/api.domain.com.crt")
}

将应用层中间件绑定到应用程序对象的实例

代码语言:javascript复制
app.use(sslify());

启动一个端口为3000 的 https 的服务

代码语言:javascript复制
https.createServer(httpsOption, app.callback()).listen(3000, (err) => {
  if (err) {
    console.log('server error', err);
  } else {
    console.log('uni-server is running in port: 3000');
  }
});

浏览器访问 https://localhost:3000

提示不安全是因为 localhost 与证书域名 api.domain.com 不符

配置数据库

在 config.js 中配置连接字符串

代码语言:javascript复制
module.exports = {
  // 数据库链接字符串
  mongoUrl: 'mongodb://db:pwd@api.domain.com:27017/db',
  // JWT
  jwtKey: 'zephyr-jwt-secret-key',
  hwtHead: {
    "typ": "JWT",
    "alg": "HS256"
  },
  jwtPayload: {
    "iss": "",                          // 签发人
    "sub": "",                          // jwt所面向的用户
    "aud": "",                          // 接收jwt的一方
    "exp": "",                          // jwt的过期时间
    "nbf": "",                          // 定义在什么时间之前,该jwt都是不可用的
    "iat": "",                          // jwt的签发时间
    "jti": "",                          // jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击
    "name": "",                         // 自定义
    "auth": ""                          // 自定义
  }
}

在 connection.js 中连接数据库

代码语言:javascript复制
const mongoose = require('mongoose');

const DB_URL = require("../config").mongoUrl;

mongoose.connect(DB_URL, { useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false })
  .then(() => console.log("we are connected"))
  .catch(error => console.log(error));

文档架构

User 架构

代码语言:javascript复制
const mongoose = require('mongoose');

const User = new mongoose.Schema({
  openid: String,
  sessionKey: String,
  info: {
    nickName: String,
    gender: Number,
    city: String,
    province: String,
    country: String,
    avatarUrl: String
  },
  createAt: Number,
  updateAt: Number
})

module.exports = mongoose.model('User', User);

控制器

User 控制器

代码语言:javascript复制
require('../db/connection');
const request = require('request-promise');
const User = require('../schemas/user');
const appid = require('../config').appid;
const secret = require('../config').secret;

class UserController {
  async getOpenId(ctx, next) {
    const code = ctx.request.query.code || null;
    const info = JSON.parse(ctx.request.query.info) || null;

    if (code) {
      try {
        const res = JSON.parse(await request({
          uri: `https://api.weixin.qq.com/sns/jscode2session?appid=${appid}&secret=${secret}&js_code=${code}&grant_type=authorization_code`
        }))

        if (res) {
          const userItem = new User({
            openId: res.openid || '',
            sessionKey: res.session_key || '',
            info: info,
            createAt: '',
            updateAt: ''
          });

          const doc = await User.find({
            openid: res.openid
          });

          // 如果openid不存在
          if (!doc) {
            userItem.createAt = Math.round(new Date() / 1000);
            userItem.updateAt = 0;
            const _save = await userItem.save();
            ctx.body = {
              code: 1,
              msg: 'ok',
              uid: res.openid,
              result: _save
            }
          } else {
            const filter = { openId: res.openid };
            const update = { sessionKey: res.session_key, info: info, updateAt: Math.round(new Date() / 1000) };

            let doc = await User.findOneAndUpdate(filter, update, (res) => {
              return res;
            });
            
            ctx.body = {
              code: 1,
              msg: 'ok',
              result: res.openid
            }
          }
        }
      } catch (err) {
        ctx.body = {
          code: 0,
          msg: err.message || 'Server error'
        }
      }
    } else {
      ctx.body = {
        code: 0,
        msg: err.message || 'Need code'
      }
    }

  }
}

module.exports = new UserController();

路由

代码语言:javascript复制
// 部分路由
const router = require('koa-router')();
const userctrl = require('../controllers/user');
const bannerctrl = require('../controllers/banner');
const goodctrl = require('../controllers/good');
const cartctrl = require('../controllers/cart');
const sortctrl = require('../controllers/sort');
const addrctrl = require('../controllers/addr');
const appraisalctrl = require('../controllers/appraisal');
const orderctrl = require('../controllers/order');
const smsctrl = require('../controllers/sms');

router
  // 用户模块
  .get('/user/openid', userctrl.getOpenId)

  // 订单模块
  .get('/pay/order', orderctrl.getOrders)
  .post('/pay/order', orderctrl.addOrder)
  .put('/pay/order', orderctrl.editOrder)
  .delete('/pay/order', orderctrl.deleteOrder)

  // 支付模块
  .post('/pay/unifiedorder', orderctrl.unifiedorOrder)
  .post('/pay/callback', orderctrl.callBack)

  // 商品模块
  .get('/source/good', goodctrl.getGood) // 通过 query?id=10001 查询单个商品,否则查询全部
  .post('/source/good', goodctrl.addGood)
  .put('/source/good', goodctrl.editGood)
  .delete('/source/good', goodctrl.deleteGood)

module.exports = router;

访问

浏览器访问 https://localhost:3000/source/good?id=10001 查询 id 为 10001 的商品

DONE !

0 人点赞