日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

springboot token_Springboot接口幂等性基于token实现方案

發(fā)布時(shí)間:2025/3/19 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 springboot token_Springboot接口幂等性基于token实现方案 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

什么是接口冪等

冪等(idempotent、idempotence)是一個(gè)數(shù)學(xué)與計(jì)算機(jī)學(xué)概念,常見(jiàn)于抽象代數(shù)中,即f(f(x)) = f(x).簡(jiǎn)單的來(lái)說(shuō)就是一個(gè)操作多次執(zhí)行產(chǎn)生的結(jié)果與一次執(zhí)行產(chǎn)生的結(jié)果一致。有些系統(tǒng)操作天生就具有冪等性例如數(shù)據(jù)庫(kù)的select語(yǔ)句,但更多時(shí)候是需要程序員來(lái)做保證的,尤其是在分布式系統(tǒng)環(huán)境中,接口能不能做到保證冪等性對(duì)系統(tǒng)的影響可能是非常大的,例如很常見(jiàn)的支付下單等場(chǎng)景,由于分布式環(huán)境中網(wǎng)絡(luò)的復(fù)雜性,用戶誤操作,網(wǎng)絡(luò)抖動(dòng),消息重復(fù),服務(wù)超時(shí)導(dǎo)致業(yè)務(wù)自動(dòng)重試等等各種情況都可能會(huì)使線上數(shù)據(jù)產(chǎn)生了不一致,造成生產(chǎn)事故。

實(shí)現(xiàn)方案

1、查詢操作:查詢一次和查詢多次,在數(shù)據(jù)不變的情況下,查詢結(jié)果是一樣的。select是天然的冪等操作;2、刪除操作:刪除操作也是冪等的,刪除一次和多次刪除都是把數(shù)據(jù)刪除。(注意可能返回結(jié)果不一樣,刪除的數(shù)據(jù)不存在,返回0,刪除的數(shù)據(jù)多條,返回結(jié)果多個(gè)) ;3、唯一索引:利用數(shù)據(jù)庫(kù)新增臟數(shù)據(jù)。比如:支付寶的資金賬戶,支付寶也有用戶賬戶,每個(gè)用戶只能有一個(gè)資金賬戶,怎么防止給用戶創(chuàng)建資金賬戶多個(gè),那么給資金賬戶表中的用戶ID加唯一索引,所以一個(gè)用戶新增成功一個(gè)資金賬戶記錄。要點(diǎn):唯一索引或唯一組合索引來(lái)防止新增數(shù)據(jù)存在臟數(shù)據(jù)(當(dāng)表存在唯一索引,并發(fā)時(shí)新增報(bào)錯(cuò)時(shí),再查詢一次就可以了,數(shù)據(jù)應(yīng)該已經(jīng)存在了,返回結(jié)果即可);4、token機(jī)制:防止頁(yè)面重復(fù)提交。采用token加redis或token加jvm內(nèi)存。處理流程:1. 數(shù)據(jù)提交前要向服務(wù)的申請(qǐng)token,token放到redis或jvm內(nèi)存,token有效時(shí)間;2. 提交后后臺(tái)校驗(yàn)token,同時(shí)刪除token,生成新的token返回。token特點(diǎn):要申請(qǐng),一次有效性,可以限流。注意:redis要用刪除操作來(lái)判斷token,刪除成功代表token校驗(yàn)通過(guò),如果用select+delete來(lái)校驗(yàn)token,存在并發(fā)問(wèn)題,不建議使用;5、分布式鎖:如果是分布式系統(tǒng)的話,構(gòu)建全局唯一索引會(huì)比較困難,比如唯一性的字段就沒(méi)有辦法確定。這時(shí)候可以引入分布式鎖,通過(guò)第三方的系統(tǒng)(Redis或Zookeeper),在業(yè)務(wù)系統(tǒng)插入數(shù)據(jù)或者更新數(shù)據(jù)前,需要先獲取分布式鎖,然后才能做操作,操作完成之后就釋放鎖。這樣其實(shí)是把單機(jī)系統(tǒng)里面多線程并發(fā)鎖的思路引入了多個(gè)系統(tǒng)的場(chǎng)景,也就是分布式系統(tǒng)中的解決思路。要點(diǎn):某個(gè)長(zhǎng)流程處理過(guò)程要求不能并發(fā)執(zhí)行,可以在流程執(zhí)行之前根據(jù)某個(gè)標(biāo)志(用戶ID+后綴等)獲取分布式鎖,其他流程執(zhí)行時(shí)獲取鎖就會(huì)失敗,也就是同一時(shí)間該流程只能有一個(gè)能執(zhí)行成功,執(zhí)行完成后,釋放分布式鎖(分布式鎖要第三方系統(tǒng)提供)。6、select + insert:在設(shè)計(jì)單據(jù)相關(guān)的業(yè)務(wù),或者是任務(wù)相關(guān)的業(yè)務(wù),肯定會(huì)涉及到狀態(tài)機(jī)(狀態(tài)變更圖)。簡(jiǎn)單理解,就是業(yè)務(wù)單據(jù)上面有個(gè)狀態(tài)的字段,狀態(tài)在不同的情況下會(huì)發(fā)生變更,一般情況下存在有限狀態(tài)機(jī)。這時(shí)候,如果狀態(tài)機(jī)已經(jīng)處于下一個(gè)狀態(tài),這時(shí)候來(lái)了一個(gè)上一個(gè)狀態(tài)的變更,理論上是不能夠變更的,這樣的話,保證了有限狀態(tài)機(jī)的冪等。注意:訂單等單據(jù)類業(yè)務(wù),存在很長(zhǎng)的狀態(tài)流轉(zhuǎn),一定要深刻理解狀態(tài)機(jī),對(duì)業(yè)務(wù)系統(tǒng)設(shè)計(jì)能力提高有很大幫助。

基于token+Redis的實(shí)現(xiàn)方案

環(huán)境:springboot2.2.11.RELEASE + Redis

  • pom.xml 依賴
org.springframework.bootspring-boot-starter-data-redisorg.springframework.bootspring-boot-starter-weborg.apache.commonscommons-pool2
  • 自定義注解類,有該注解的需要驗(yàn)證token是否有效
@Documented@Inherited@Retention(RUNTIME)@Target({ METHOD, TYPE})public @interface ApiIdempotent {}
  • 攔截器定義,攔截請(qǐng)求方法進(jìn)行token有效性驗(yàn)證
public class MethodIdempotentCheck implements HandlerInterceptor {private Logger logger = LoggerFactory.getLogger(MethodIdempotentCheck.class) ;@Resourceprivate StringRedisTemplate stringRedisTemplate ;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {if (handler instanceof HandlerMethod) {HandlerMethod handlerMethod = (HandlerMethod) handler ;Method method = handlerMethod.getMethod() ;Class> clazz = method.getClass() ;if (clazz.isAnnotationPresent(ApiIdempotent.class)) {if (!checkToken(request)) {failure(response) ;return false ;}} else {if (method.isAnnotationPresent(ApiIdempotent.class)) {if (!checkToken(request)) {failure(response) ;return false ;}}}}return true ;}private void failure(HttpServletResponse response) throws Exception {response.setContentType("application/json;charset=utf-8") ;response.getWriter().write("{"code": -1, "message": "重復(fù)提交"}") ;}private boolean checkToken(HttpServletRequest request) {logger.info("驗(yàn)證token") ;String token = request.getParameter("access-token") ;if (token == null || token.length() == 0) {token = request.getHeader("access-token") ;}logger.info("獲取token:{}", token) ;if (token == null || token.length() == 0) {return false ;}boolean exists = stringRedisTemplate.hasKey(token) ;if (!exists) {return false ;}return stringRedisTemplate.delete(token) ;}}token會(huì)從header中獲取請(qǐng)求參數(shù)中獲取。
  • WebConfig 配置攔截器
@Configurationpublic class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(tokenInterceptor()) ;}@Beanpublic HandlerInterceptor tokenInterceptor() {return new MethodIdempotentCheck() ;}}
  • Controller 測(cè)試
@RestController@RequestMapping("/demo")public class DemoController {@Resourceprivate StringRedisTemplate stringRedisTemplate ;/** * 生成Token;這里token的有效期設(shè)置了10分鐘。 * @return */@GetMapping("/create")public Object create() {String access_token = UUID.randomUUID().toString() ;stringRedisTemplate.opsForValue().set(access_token, access_token, 10, TimeUnit.MINUTES) ;return access_token ;}@PostMapping("/save")@ApiIdempotentpublic Object business(@RequestBody Users user) {Map result = new HashMap<>() ;// todo save Usersresult.put("code", 0) ;result.put("message", "創(chuàng)建成功") ;return result ;}}

business 方法加入了@ApiIdempotent注解,表示該方法需要進(jìn)行token驗(yàn)證是否有效的請(qǐng)求

整個(gè)請(qǐng)求流程要先獲取token,然后將得到的token放入header中或者請(qǐng)求參數(shù)中。

測(cè)試:

獲取token:

請(qǐng)求業(yè)務(wù)方法將獲取的token 添加到header中

再次請(qǐng)求:

每次請(qǐng)求token的驗(yàn)證是通過(guò)刪除token進(jìn)行的,所以當(dāng)?shù)诙卧僬?qǐng)求時(shí),redis中已經(jīng)沒(méi)有了token所以這里就提示:重復(fù)提交了。

完畢!!!

給個(gè)關(guān)注,轉(zhuǎn)發(fā),謝謝

SpringBoot RabbitMQ消息可靠發(fā)送與接收

SpringBoot中使用Cache及JSR107的使用

SpringBoot開(kāi)發(fā)自己的Starter

SpringBoot開(kāi)發(fā)自己的@Enable功能

Java線上CPU100% 問(wèn)題排查

Restful API設(shè)計(jì)規(guī)范

SpringCloud Nacos 服務(wù)動(dòng)態(tài)配置

SpringCloud Nacos 服務(wù)消費(fèi)者

SpringCloud Nacos 服務(wù)提供者

SpringCloud Alibaba 之 Nacos 服務(wù)

Spring Cloud Nacos 開(kāi)啟權(quán)限驗(yàn)證

SpringCloud Nacos 整合feign

SpringCloud Hystrix實(shí)現(xiàn)資源隔離應(yīng)用

Alibaba Sentinel動(dòng)態(tài)規(guī)則(Nacos數(shù)據(jù)源)

SpringCloud zuul 動(dòng)態(tài)網(wǎng)關(guān)配置

總結(jié)

以上是生活随笔為你收集整理的springboot token_Springboot接口幂等性基于token实现方案的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。