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





边栏推荐
- MAUI Developer Day in GCR
- 嵌入式軟件測試怎麼實現自動化測試?
- QT:QSS自定义QLineEdit实例
- 有些能力,是工作中学不来的,看看这篇超过90%同行
- Extern keyword
- Flink < --> Introduction to JDBC +with parameter
- Qt:qss custom qpprogressbar instance
- Logstash backup tracks the data records reported
- Qt:qss custom qmenubar instance
- Communication software development and Application
猜你喜欢

Snownlp emotion analysis

那些一门心思研究自动化测试的人,后来怎样了?

Solve the problem that pycharm Chinese input method does not follow

12. Nacos server service registration of source code analysis of Nacos service registration

QT:QSS自定义QTableView实例

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

What kind of living condition is a tester with a monthly salary of more than 10000?

How to monitor the incoming and outgoing traffic of the server host?

MAUI Developer Day in GCR

What are the strengths of "testers"?
随机推荐
Qt:qss custom qpprogressbar instance
Is pinduogai's sales safe in 2022?
Qt:qss custom qlineedit instance
After 8 years of industry thinking, the test director has a deeper understanding of test thinking
Win10系统下提示“系统组策略禁止安装此设备”的解决方案(家庭版无组策略)
Qt:qss custom qlistview instance
那些一门心思研究自动化测试的人,后来怎样了?
Imread change image display size
可以写进简历的软件测试电商项目,不进来get一下?
Hard goods | write all the codes as soon as you change the test steps? Why not try yaml to realize data-driven?
Have you learned the new technology to improve sales in 2021?
Redis notes 01: Introduction
你真的需要自动化测试吗?
测试理论概述
栈,单调栈,队列,单调队列
软件测试必学基本理论知识——APP测试
The highest monthly salary of 18K has a good "mentality and choice", and success is poor "seriousness and persistence"~
What kind of living condition is a tester with a monthly salary of more than 10000?
11. Provider service registration of Nacos service registration source code analysis
.Net Core-做一个微信公众号的排队系统