当前位置:网站首页>封装一个koa分布式锁中间件来解决幂等或重复请求的问题
封装一个koa分布式锁中间件来解决幂等或重复请求的问题
2022-07-03 09:46:00 【InfoQ】
import ioredis from 'ioredis'
import { REDIS_CONF } from '../config/db'
const { password, port, host } = REDIS_CONF
class Redis {
client
constructor() {
this.client = new ioredis({
port,
host,
password
})
this.client.on('error', (err) => console.log(err))
}
//添加数据
async set(key: string, value: any, time?: number | string) {
//判断value值是否是对象类型
if (typeof value === 'object') {
value = JSON.stringify(value)
}
//time为过期时间,可选
if (time) {
await this.client.set(key, value, 'EX', time)
} else {
await this.client.set(key, value)
}
}
async get(key: string) {
const data = await this.client.get(key)
return data
}
async delete(key: string) {
await this.client.del(key)
}
}
const redis = new Redis()
export default redisimport Redlock from 'redlock'
import redis from './redis'
const redlock = new Redlock([redis.client], { retryCount: 0 })
export default redlockimport { Middleware } from 'koa'
import { Lock } from 'redlock'
import redlock from '../db/redlock'
import { error } from '../utils/Response'
//这里isByUser为true则由用户id+请求地址作为key上锁,即:此接口不允许一个用户同时更改同一资源(参数不同也不行)
//isByUser默认为false则由全部参数+用户id+地址作为key上锁,即:此接口不允许一个用户同时以同一参数更改同一资源(拦截重复请求)
const idempotent = (isByUser: boolean = false) => {
const Redlock: Middleware = async (ctx, next) => {
let id: string
//这里的ctx.user是我之前配置的中间件,用于解析用户携带token的参数,来辨别用户和获取用户参数,里面存放用户的个人信息
//有的接口不需要鉴权认证,所以ctx.user.id就会报错则id以空字符串输出
/*这里为什么要解析出id而不是直接拿token呢?因为一个用户可以有多个token,但一个用户只有一个id
如果拿token作为标识,不同token的同一用户也会成功上锁,就形成了一个用户多次获得了锁的情况
但由于id的独立性,所以id不同,就表示为不同的用户了
*/
try {
id = ctx.user.id
} catch (error) {
id = ''
}
let lock: Lock | null = null
try {
if (isByUser) {
//上锁
lock = await redlock.acquire([`${id}:${ctx.URL}`], 10000)
} else {
const body = JSON.stringify(ctx.request.body)
console.log(`${id}:${ctx.URL}:${body}`)
lock = await redlock.acquire([`${id}:${ctx.URL}:${body}`], 10000)
}
} catch (err) {
//如果抛出错误表示上锁失败,表示有重复请求正在操作
//这里的error()函数是我封装的返回错误的函数里面调用了ctx.throw所以报错会立即返回,后面的next不会继续进行
error(ctx, 500, '请求正在进行,请勿重复提交')
}
await next()
//后面的中间件全部执行完就可以释放锁了
await lock!.release()
}
return Redlock
}
export default idempotent





边栏推荐
- IIS does not take effect after modifying the configuration information
- Solution: jupyter notebook does not pop up the default browser
- Word line and bit line
- Overview of testing theory
- Qt:qss custom qheaderview instance
- 《通信软件开发与应用》
- 2021 postgraduate entrance examination mathematics 2 linear algebra
- 测试Leader应该做哪些事
- QT: QSS custom qsplitter instance
- ByteDance layoffs, test engineers were almost destroyed: how terrible is the routine behind the recruitment of large factories?
猜你喜欢

软件测试——Redis数据库

After 8 years of industry thinking, the test director has a deeper understanding of test thinking

Communication software development and Application

The testing department of the company came to the king of the Post-00 roll, and the veteran exclaimed that it was really dry, but

可以写进简历的软件测试电商项目,不进来get一下?

你真的需要自动化测试吗?

软件测试必学基本理论知识——APP测试

What happened to those who focused on automated testing?

Differences among norm, normalize and normalized in eigen

QT:QSS自定义 QTreeView实例
随机推荐
Imread change image display size
Basic theoretical knowledge of software testing -- app testing
Flink < --> Introduction to JDBC +with parameter
Flink-- custom function
Qt:qss custom qpprogressbar instance
反正切熵(Arctangent entropy):2022.7月最新SCI论文
Clion debug
File upload and download test point
QT: QSS custom qtoolbutton instance
【蓝桥杯选拔赛真题44】Scratch消灭骷髅军团 少儿编程scratch蓝桥杯选拔赛真题讲解
Summary of the history of Mathematics
Communication software development and Application
Hard goods | write all the codes as soon as you change the test steps? Why not try yaml to realize data-driven?
独家分析 | 关于简历和面试的真 相
Lecture 1 number field
How to monitor the incoming and outgoing traffic of the server host?
QT:QSS自定义QGroupBox实例
IIS修改配置信息后不生效
The testing department of the company came to the king of the Post-00 roll, and the veteran exclaimed that it was really dry, but
嵌入式軟件測試怎麼實現自動化測試?