亚洲精品中文免费|亚洲日韩中文字幕制服|久久精品亚洲免费|一本之道久久免费

      
      

            <dl id="hur0q"><div id="hur0q"></div></dl>

                處理接口冪等性的兩種常見(jiàn)方案

                在上周發(fā)布的 TienChin 項(xiàng)目視頻中,我和大家一共梳理了六種冪等性解決方案,接口冪等性處理算是一個(gè)非常常見(jiàn)的需求了,我們?cè)诤芏囗?xiàng)目中其實(shí)都會(huì)遇到。今天我們來(lái)看看兩種比較簡(jiǎn)單的實(shí)現(xiàn)思路。

                1. 接口冪等性實(shí)現(xiàn)方案梳理

                其實(shí)接口冪等性的實(shí)現(xiàn)方案還是蠻多的,我這里和小伙伴們分享兩種比較常見(jiàn)的方案。

                1.1 基于 Token

                基于 Token 這種方案的實(shí)現(xiàn)思路很簡(jiǎn)單,整個(gè)流程分兩步:

              1. 客戶端發(fā)送請(qǐng)求,從服務(wù)端獲取一個(gè) Token 令牌,每次請(qǐng)求獲取到的都是一個(gè)全新的令牌。
              2. 客戶端發(fā)送請(qǐng)求的時(shí)候,攜帶上第一步的令牌,處理請(qǐng)求之前,先校驗(yàn)令牌是否存在,當(dāng)請(qǐng)求處理成功,就把令牌刪除掉。
              3. 大致的思路就是上面這樣,當(dāng)然具體的實(shí)現(xiàn)則會(huì)復(fù)雜很多,有很多細(xì)節(jié)需要注意,松哥之前也專門(mén)錄過(guò)這種方案的視頻,小伙伴們可以參考下,錄了兩個(gè)視頻,一個(gè)是基于攔截器處理的,還有一個(gè)是基于 AOP 切面處理的:

                基于攔截器處理(視頻一):

                基于 AOP 切面處理(視頻二):

                1.2 基于請(qǐng)求參數(shù)校驗(yàn)

                最近在 TienChin 項(xiàng)目中使用的是另外一種方案,這種方案是基于請(qǐng)求參數(shù)來(lái)判斷的,如果在短時(shí)間內(nèi),同一個(gè)接口接收到的請(qǐng)求參數(shù)相同,那么就認(rèn)為這是重復(fù)的請(qǐng)求,拒絕處理,大致上就是這么個(gè)思路。

                相比于第一種方案,第二種方案相對(duì)來(lái)說(shuō)省事一些,因?yàn)橹挥幸淮握?qǐng)求,不需要專門(mén)去服務(wù)端拿令牌。在高并發(fā)環(huán)境下這種方案優(yōu)勢(shì)比較明顯。

                所以今天我就來(lái)和大家聊聊第二種方案的實(shí)現(xiàn),后面在 TienChin 項(xiàng)目視頻中也會(huì)和大家細(xì)講。

                2. 基于請(qǐng)求參數(shù)的校驗(yàn)

                首先我們新建一個(gè) Spring Boot 項(xiàng)目,引入 Web 和 Redis 依賴,新建完成后,先來(lái)配置一下 Redis 的基本信息,如下:

                spring.redis.host=localhostspring.redis.port=6379spring.redis.password=123

                為了后續(xù) Redis 操作方便,我們?cè)賮?lái)對(duì) Redis 進(jìn)行一個(gè)簡(jiǎn)單封裝,如下:

                @Componentpublic class RedisCache { @Autowired public RedisTemplate redisTemplate; public void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) { redisTemplate.opsForValue().set(key, value, timeout, timeUnit); } public T getCacheObject(final String key) { ValueOperations operation = redisTemplate.opsForValue(); return operation.get(key); }}

                這個(gè)比較簡(jiǎn)單,一個(gè)存數(shù)據(jù),一個(gè)讀數(shù)據(jù)。

                接下來(lái)我們自定義一個(gè)注解,在需要進(jìn)行冪等性處理的接口上,添加該注解即可,將來(lái)這個(gè)接口就會(huì)自動(dòng)的進(jìn)行冪等性處理。

                @Inherited@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface RepeatSubmit { /** * 間隔時(shí)間(ms),小于此時(shí)間視為重復(fù)提交 */ public int interval() default 5000; /** * 提示消息 */ public String message() default “不允許重復(fù)提交,請(qǐng)稍候再試”;}

                這個(gè)注解我們通過(guò)攔截器來(lái)進(jìn)行解析,解析代碼如下:

                public abstract class RepeatSubmitInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class); if (annotation != null) { if (this.isRepeatSubmit(request, annotation)) { Map map = new HashMap(); map.put(“status”, 500); map.put(“msg”, annotation.message()); response.setContentType(“application/json;charset=utf-8”); response.getWriter().write(new ObjectMapper().writeValueAsString(map)); return false; } } return true; } else { return true; } } /** * 驗(yàn)證是否重復(fù)提交由子類(lèi)實(shí)現(xiàn)具體的防重復(fù)提交的規(guī)則 * * @param request * @return * @throws Exception */ public abstract boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation);}

                這個(gè)攔截器是一個(gè)抽象類(lèi),將接口方法攔截下來(lái),然后找到接口上的 @RepeatSubmit 注解,調(diào)用 isRepeatSubmit 方法去判斷是否是重復(fù)提交的數(shù)據(jù),該方法在這里是一個(gè)抽象方法,我們需要再定義一個(gè)類(lèi)繼承自這個(gè)抽象類(lèi),在新的子類(lèi)中,可以有不同的冪等性判斷邏輯,這里我們就是根據(jù) URL 地址+參數(shù) 來(lái)判斷冪等性條件是否滿足:

                @Componentpublic class SameUrlDataInterceptor extends RepeatSubmitInterceptor { public final String REPEAT_PARAMS = “repeatParams”; public final String REPEAT_TIME = “repeatTime”; public final static String REPEAT_SUBMIT_KEY = “REPEAT_SUBMIT_KEY”; private String header = “Authorization”; @Autowired private RedisCache redisCache; @SuppressWarnings(“unchecked”) @Override public boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation) { String nowParams = “”; if (request instanceof RepeatedlyRequestWrapper) { RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request; try { nowParams = repeatedlyRequest.getReader().readLine(); } catch (IOException e) { e.printStackTrace(); } } // body參數(shù)為空,獲取Parameter的數(shù)據(jù) if (StringUtils.isEmpty(nowParams)) { try { nowParams = new ObjectMapper().writeValueAsString(request.getParameterMap()); } catch (JsonProcessingException e) { e.printStackTrace(); } } Map nowDataMap = new HashMap(); nowDataMap.put(REPEAT_PARAMS, nowParams); nowDataMap.put(REPEAT_TIME, System.currentTimeMillis()); // 請(qǐng)求地址(作為存放cache的key值) String url = request.getRequestURI(); // 唯一值(沒(méi)有消息頭則使用請(qǐng)求地址) String submitKey = request.getHeader(header); // 唯一標(biāo)識(shí)(指定key + url + 消息頭) String cacheRepeatKey = REPEAT_SUBMIT_KEY + url + submitKey; Object sessionObj = redisCache.getCacheObject(cacheRepeatKey); if (sessionObj != null) { Map sessionMap = (Map) sessionObj; if (compareParams(nowDataMap, sessionMap) && compareTime(nowDataMap, sessionMap, annotation.interval())) { return true; } } redisCache.setCacheObject(cacheRepeatKey, nowDataMap, annotation.interval(), TimeUnit.MILLISECONDS); return false; } /** * 判斷參數(shù)是否相同 */ private boolean compareParams(Map nowMap, Map preMap) { String nowParams = (String) nowMap.get(REPEAT_PARAMS); String preParams = (String) preMap.get(REPEAT_PARAMS); return nowParams.equals(preParams); } /** * 判斷兩次間隔時(shí)間 */ private boolean compareTime(Map nowMap, Map preMap, int interval) { long time1 = (Long) nowMap.get(REPEAT_TIME); long time2 = (Long) preMap.get(REPEAT_TIME); if ((time1 – time2) < interval) { return true; } return false; }}

                我們來(lái)看下具體的實(shí)現(xiàn)邏輯:

              4. 首先判斷當(dāng)前的請(qǐng)求對(duì)象是不是 RepeatedlyRequestWrapper,如果是,說(shuō)明當(dāng)前的請(qǐng)求參數(shù)是 JSON,那么就通過(guò) IO 流將參數(shù)讀取出來(lái),這塊小伙伴們要結(jié)合上篇文章共同來(lái)理解,否則可能會(huì)覺(jué)得云里霧里的,傳送門(mén)JSON 數(shù)據(jù)讀一次就沒(méi)了,怎么辦?。
              5. 如果在第一步中,并沒(méi)有拿到參數(shù),那么說(shuō)明參數(shù)可能并不是 JSON 格式,而是 key-value 格式,那么就以 key-value 的方式讀取出來(lái)參數(shù),并將之轉(zhuǎn)為一個(gè) JSON 字符串。
              6. 接下來(lái)構(gòu)造一個(gè) Map,將前面讀取到的參數(shù)和當(dāng)前時(shí)間存入到 Map 中。
              7. 接下來(lái)構(gòu)造存到 Redis 中的數(shù)據(jù)的 key,這個(gè) key 由固定前綴 + 請(qǐng)求 URL 地址 + 請(qǐng)求頭的認(rèn)證令牌組成,這塊請(qǐng)求頭的令牌還是非常重要需要有的,只有這樣才能區(qū)分出來(lái)當(dāng)前用戶提交的數(shù)據(jù)(如果是 RESTful 風(fēng)格的接口,那么為了區(qū)分,也可以將接口的請(qǐng)求方法作為參數(shù)拼接到 key 中)。
              8. 接下來(lái)就去 Redis 中獲取數(shù)據(jù),獲取到之后,分別去比較參數(shù)是否相同以及時(shí)間是否過(guò)期。
              9. 如果判斷都沒(méi)問(wèn)題,返回 true,表示這個(gè)請(qǐng)求重復(fù)了。
              10. 否則返回說(shuō)明這是用戶對(duì)這個(gè)接口第一次提交數(shù)據(jù)或者是已經(jīng)過(guò)了時(shí)間窗口了,那么就把參數(shù)字符串重新緩存到 Redis 中,并返回 false,表示請(qǐng)求沒(méi)問(wèn)題。
              11. 好啦,做完這一切,最后我們?cè)賮?lái)配置一下攔截器即可:

                @Configurationpublic class WebConfig implements WebMvcConfigurer { @Autowired RepeatSubmitInterceptor repeatSubmitInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(repeatSubmitInterceptor) .addPathPatterns(“/**”); }}

                如此,我們的接口冪等性就處理好啦 在需要的時(shí)候,就可以直接在接口上使用啦:

                @RestControllerpublic class HelloController { @PostMapping(“/hello”) @RepeatSubmit(interval = 100000) public String hello(@RequestBody String msg) { System.out.println(“msg = ” + msg); return “hello”; }}

                好啦,公眾號(hào)后臺(tái)回復(fù) RepeatSubmit 可以下載本文源碼哦。

                鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場(chǎng),版權(quán)歸原作者所有,如有侵權(quán)請(qǐng)聯(lián)系管理員(admin#wlmqw.com)刪除。
                用戶投稿
                上一篇 2022年6月21日 09:05
                下一篇 2022年6月21日 09:05

                相關(guān)推薦

                • 抖音只說(shuō)了封禁沒(méi)說(shuō)時(shí)長(zhǎng)(抖音封禁一般多長(zhǎng)時(shí)間)

                  最近是不是發(fā)現(xiàn)抖音監(jiān)管和封號(hào)的力度大了很多,我常能看到,有同學(xué)吐槽,為什么又被封了,我也沒(méi)有違規(guī)呀??! 那么今天,我就列出4大容易被封的原因,幫你避開(kāi)90%的坑。學(xué)會(huì)了就點(diǎn)贊吧。 …

                  2022年11月27日
                • 分享4條發(fā)微商朋友圈的方法(微商朋友圈應(yīng)該怎么發(fā))

                  對(duì)于微商朋友來(lái)說(shuō),朋友圈的重要性不言而喻了。 那么微商的朋友圈到底該怎么發(fā)呢? 為什么同樣是經(jīng)營(yíng)一個(gè)朋友圈,有的微商看起來(lái)逼格滿滿,實(shí)際效果也不錯(cuò);而有的卻動(dòng)都不動(dòng)就被屏蔽甚至拉黑…

                  2022年11月27日
                • 30個(gè)無(wú)加盟費(fèi)的項(xiàng)目(茶顏悅色奶茶店加盟費(fèi)多少)

                  茶顏悅色又爆了,8月18日,茶顏悅色南京門(mén)店正式開(kāi)業(yè),開(kāi)張不到半小時(shí),門(mén)店就人滿為患,消費(fèi)者的購(gòu)買(mǎi)熱情十分高漲,而由于人流量過(guò)大造成擁堵,茶顏悅色也不得不暫停營(yíng)業(yè)。 當(dāng)然,這里面排…

                  2022年11月27日
                • 短視頻策劃內(nèi)容的3個(gè)要點(diǎn)(短視頻策劃內(nèi)容怎么做)

                  短視頻在制作時(shí),內(nèi)容框架非常重要。如果直奔主題,然后結(jié)束,聚卓告訴你,這樣的短視頻已經(jīng)過(guò)時(shí)了。現(xiàn)在的短視頻需要框架的,但不是任何框架,它需要一種易于理解和消化的框架。而且,現(xiàn)在大多…

                  2022年11月27日
                • 存儲(chǔ)過(guò)程語(yǔ)法(sql server存儲(chǔ)過(guò)程語(yǔ)法)

                  今天小編給各位分享存儲(chǔ)過(guò)程語(yǔ)法的知識(shí),其中也會(huì)對(duì)sql server存儲(chǔ)過(guò)程語(yǔ)法進(jìn)行解釋,如果能碰巧解決你現(xiàn)在面臨的問(wèn)題,別忘了關(guān)注本站,現(xiàn)在開(kāi)始吧! oracle存儲(chǔ)過(guò)程基本語(yǔ)法…

                  2022年11月26日
                • 凈利潤(rùn)率越高越好嗎(凈利潤(rùn)率多少合適)

                  一、持續(xù)增收不增利,平均凈利潤(rùn)率首次跌入個(gè)位數(shù) 2021年,增收不增利依舊是行業(yè)主流。具體來(lái)看,大部分企業(yè)營(yíng)業(yè)收入呈增長(zhǎng)態(tài)勢(shì),E50企業(yè)平均同比增速達(dá)到17.3%,但是利潤(rùn)增速則明…

                  2022年11月26日
                • 個(gè)人怎么做抖音帶貨(個(gè)人做抖音帶貨能賺錢(qián)嗎)

                  抖音如今是大家很熟悉的短視頻平臺(tái),不過(guò)現(xiàn)在的抖音卻不只是短視頻那么簡(jiǎn)單,它的功能非常豐富,其中一個(gè)就是可以帶貨,相信很多小伙伴都有在抖音上買(mǎi)過(guò)東西,抖音如今的變現(xiàn)能力也是不容小覷的…

                  2022年11月25日
                • 全民K歌升級(jí)新版本7.0之后,有哪些隱藏功能?

                  作者:高百烈來(lái)源:知乎 這個(gè)功能,舊版并沒(méi)有,要升級(jí)到全新的全民K歌7.0版本才能發(fā)現(xiàn)。 作為朋友圈當(dāng)代K歌之王,我費(fèi)了不少功夫才搶到內(nèi)測(cè)版本。有一說(shuō)一,全民K歌的路子真的很野,新…

                  2022年11月25日
                • 《寶可夢(mèng)朱紫》夢(mèng)特性怎么獲得?隱藏特性獲取方法推薦

                  寶可夢(mèng)朱紫里有很多寶可夢(mèng)都是擁有夢(mèng)特性會(huì)變強(qiáng)的寶可夢(mèng),很多玩家不知道夢(mèng)特性怎么獲得,下面就給大家?guī)?lái)寶可夢(mèng)朱紫隱藏特性獲取方法推薦,感興趣的小伙伴一起來(lái)看看吧,希望能幫助到大家。 …

                  2022年11月25日
                • 《寶可夢(mèng)朱紫》奇魯莉安怎么進(jìn)化?奇魯莉安進(jìn)化方法分享

                  寶可夢(mèng)朱紫中的奇魯莉安要怎么進(jìn)化呢?很多玩家都不知道,下面就給大家?guī)?lái)寶可夢(mèng)朱紫奇魯莉安進(jìn)化方法分享,感興趣的小伙伴一起來(lái)看看吧,希望能幫助到大家。 奇魯莉安進(jìn)化方法分享 奇魯莉安…

                  2022年11月25日

                聯(lián)系我們

                聯(lián)系郵箱:admin#wlmqw.com
                工作時(shí)間:周一至周五,10:30-18:30,節(jié)假日休息