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





边栏推荐
猜你喜欢
随机推荐
Qt:qss custom qspinbox instance
My understanding of testing (summarized by senior testers)
MAUI Developer Day in GCR
IIS修改配置信息后不生效
嵌入式軟件測試怎麼實現自動化測試?
How can UI automated testing get out of trouble? How to embody the value?
字节跳动大裁员,测试工程师差点遭团灭:大厂招人背后的套路,有多可怕?
如何让让别人畏惧你
QT:QSS自定义 QProgressBar实例
Stack, monotone stack, queue, monotone queue
公司测试部门来了个00后卷王之王,老油条感叹真干不过,但是...
After 8 years of industry thinking, the test director has a deeper understanding of test thinking
I, a tester from a large factory, went to a state-owned enterprise with a 50% pay cut. I regret it
Test what the leader should do
测试理论概述
Comment réaliser des tests automatisés pour les tests logiciels embarqués?
What are the strengths of "testers"?
12. Nacos server service registration of source code analysis of Nacos service registration
Flink-- custom function
Qt:qss custom qheaderview instance








