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





边栏推荐
- 那些一门心思研究自动化测试的人,后来怎样了?
- Flink chain conditional source code analysis
- Qt:qss custom qmenubar instance
- Matlab memory variable management command
- ByteDance layoffs, test engineers were almost destroyed: how terrible is the routine behind the recruitment of large factories?
- QT: QSS custom qtoolbar and qtoolbox instances
- glassfish org. h2.server. Shutdownhandler classnotfoundexception exception exception handling
- QT:QSS自定义QGroupBox实例
- 做软件测试三年,薪资不到20K,今天,我提出了辞职…
- TypeScript学习总结
猜你喜欢

I, a tester from a large factory, went to a state-owned enterprise with a 50% pay cut. I regret it

Snownlp emotion analysis

Day 7 small exercise

8年测试总监的行业思考,看完后测试思维认知更深刻

使用ML.NET+ONNX预训练模型整活B站经典《华强买瓜》

Tencent micro app to get wechat user information

【蓝桥杯选拔赛真题44】Scratch消灭骷髅军团 少儿编程scratch蓝桥杯选拔赛真题讲解

QT: QSS custom qtreeview instance

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

Exclusive analysis | truth about resume and interview
随机推荐
Qt:qss custom qspinbox instance
glassfish org. h2.server. Shutdownhandler classnotfoundexception exception exception handling
Basic theoretical knowledge of software testing -- app testing
Word line and bit line
Qt:qss custom qpprogressbar instance
Small file special
Cache routing component
做软件测试三年,薪资不到20K,今天,我提出了辞职…
Programming examples of stm32f1 and stm32subeide -tm1637 drives 4-bit 7-segment nixie tubes
文件上传下载测试点
Solve the problem that pycharm Chinese input method does not follow
Extern keyword
2021 postgraduate entrance examination mathematics 2 linear algebra
Error installing the specified version of pilot
What happened to those who focused on automated testing?
Logstash backup tracks the data records reported
Qt:qss custom qstatusbar instance
使用ML.NET+ONNX预训练模型整活B站经典《华强买瓜》
EPS电动转向系统分析
Software testing (test case) writing: vulgar, native and skillful