当前位置:网站首页>封装一个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





边栏推荐
- Probability theory: application of convolution in calculating moving average
- 多路IO转接——前导
- glassfish org. h2.server. Shutdownhandler classnotfoundexception exception exception handling
- The normal one inch is 25.4 cm, and the image field is 16 cm
- Error installing the specified version of pilot
- Typescript learning summary
- The role and necessity of implementing serializable interface
- snownlp情感分析
- QT:QSS自定义QGroupBox实例
- 可以写进简历的软件测试电商项目,不进来get一下?
猜你喜欢

17K薪资要什么水平?来看看95后测试工程师的面试全过程…

“测试人”,有哪些厉害之处?

What is the salary level of 17k? Let's take a look at the whole interview process of post-95 Test Engineers

Is it OK to test the zero basis software?

Qt:qss custom qscrollbar instance

2021 reading summary (continuously updating)

QT: QSS custom qtabwidget and qtabbar instances

Clion debug

What happened to those who focused on automated testing?

Probability theory: application of convolution in calculating moving average
随机推荐
Cache routing component
How can UI automated testing get out of trouble? How to embody the value?
Hard goods | write all the codes as soon as you change the test steps? Why not try yaml to realize data-driven?
公司测试部门来了个00后卷王之王,老油条感叹真干不过,但是...
公司里只有一个测试是什么体验?听听他们怎么说吧
QT:QSS自定义 QStatusBar实例
IIS does not take effect after modifying the configuration information
Typescript learning summary
.Net Core-做一个微信公众号的排队系统
《通信软件开发与应用》
php如何解决高并发问题
Qt:qss custom qscrollbar instance
你真的需要自动化测试吗?
QT: QSS custom qtableview instance
8年测试工程师总结出来的《测试核心价值》与《0基础转行软件测试超全学习指南》
Matlab memory variable management command
QT:QSS自定义 QProgressBar实例
我对测试工作的一些认识(资深测试人员总结)
软件测试工程师的5年之痒,讲述两年突破瓶颈经验
QT:QSS自定义QTableView实例