使用 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 !