阿里P7告訴你SpringBoot如何防止重復(fù)提交朱转?

有兩種防止重復(fù)提交:

  1. 禁用提交按鈕
  2. 發(fā)出請求令牌/ ID:

禁用提交按鈕

我們可以在函數(shù)調(diào)用HTTP請求之前禁用提交按鈕准谚,并在完成HTTP響應(yīng)后再次啟用它。該技術(shù)對于需要很長時間才能完成的過程(超過5秒)是有效的贯莺。由于不耐煩而無法獲得結(jié)果风喇,用戶無法再次單擊n'。此外缕探,我們可能會顯示一個正在Loading裝載進度魂莫,以獲得良好的體驗。

<!DOCTYPE html>
<html lang="en">

<head>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
</head>

<body>
    <form name="form-payment" id="form-payment">
        ...
    </form>

    <script type="text/javascript">
        $('#form-payment').submit(function (e) {
            e.preventDefault();
            $.ajax({
                type: 'POST',
                dataType : "json",
                contentType: "application/json; charset=utf-8",
                url: "#",
                data: "{}",
                beforeSend: function(){
                    $('#button-submit').attr('disabled', 'disable');
                },
                complete: function(){
                    $('#button-submit').removeAttr('disabled');
                },
                success: function (data) {
                        // do your success action
                },
                error: function () {
                        // do your error handler
                }
            });
        });
    </script>
</body>

在beforeSend 和complete段爹耗,我添加“ disable”屬性作為開關(guān), (jquery中有專門語句防止二次提交)

重點來了:

Spring Boot中如何發(fā)出請求令牌/ ID

這種技術(shù)實際上更復(fù)雜耙考,更難實現(xiàn),但是由于一個好的框架(如Spring Boot)使這更容易潭兽。在我們開始代碼實現(xiàn)之前倦始,讓我們先討論一下這個機制;

  • 加載表單頁面時,發(fā)出新的requestId
  • 在調(diào)用后端服務(wù)之前將已發(fā)出的requestId發(fā)送到HTTP頭
  • 后端服務(wù)標識requestId是否已注冊
  • 如果requestId已經(jīng)注冊山卦,那么我們可以將其標記為違規(guī)請求

我們來開始代碼鞋邑。這里是我的JavaScript中的示例代碼,用于發(fā)出新的requestId账蓉。

 $(document).ready(function () {
        var requestId = new Date().getTime(); // <--- issue new requestId every time page laoded 
       
        $('#form-payment').submit(function (e) {
            e.preventDefault();
            $.ajax({
                type: 'POST',
                dataType : "json",
                contentType: "application/json; charset=utf-8",
                headers: { "requestId" : requestId }, // <--- add requestId in header
                url: "#",
                data: "{}",
                beforeSend: function(){
                    $('#button-submit').attr('disabled', 'disable');
                },
                complete: function(){
                    $('#button-submit').removeAttr('disabled');
                },
                success: function (data) {
                
                },
                error: function () {
                
                }
            });
        });
    });

這里是我的Spring Boot項目中的示例代碼枚碗,我創(chuàng)建了一個Interceptor來處理requestId:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;

@Configuration
public class Interceptor implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new ViolationInterceptor()).addPathPatterns("/**");
    }

    public class ViolationInterceptor extends HandlerInterceptorAdapter {
        private List<String> requestIds = new ArrayList<>();

        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            String requestId = request.getHeader("requestId");

            if (requestIds.contains(requestId))
                throw new IllegalArgumentException("Violation Request; Reason requestId already registered");

            requestIds.add(requestId);
            return super.preHandle(request, response, handler);
        }
    }
}

Exception處理:

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class ExceptionAdvisor {

    @ExceptionHandler(IllegalArgumentException.class)
    ResponseEntity illegalArgumentExceptionHandler(IllegalArgumentException e){
        return ResponseEntity.ok(e.getMessage());
    }
}

在此示例中,我使用應(yīng)用程序內(nèi)存來??存儲requestId铸本。對于認真的開發(fā)肮雨,我建議使用內(nèi)存數(shù)據(jù)庫,例如Redis箱玷。

實際上酷含,我們可以在識別requestId時修改如何發(fā)布新令牌和邏輯。因為這個過程非常簡單汪茧,我們需要一些東西(requestId)來識別已經(jīng)請求過的東西。

歡迎大家加入粉絲交流群:963944895限番,免費分享Spring框架舱污、Mybatis框架SpringBoot框架、SpringMVC框架弥虐、SpringCloud微服務(wù)扩灯、Dubbo框架、Redis緩存霜瘪、RabbitMq消息珠插、JVM調(diào)優(yōu)、Tomcat容器颖对、MySQL數(shù)據(jù)庫教學(xué)視頻及架構(gòu)學(xué)習(xí)思維導(dǎo)圖

寫在最后:

如需Java架構(gòu)資料捻撑,點關(guān)注,發(fā)簡信給我即可,先到先得顾患!
既然看到這里了番捂,覺得筆者寫的還不錯的就點個贊,加個關(guān)注唄江解!點關(guān)注设预,不迷路,持續(xù)更新@绾印1钫怼!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末桨螺,一起剝皮案震驚了整個濱河市宾符,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌彭谁,老刑警劉巖吸奴,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異缠局,居然都是意外死亡则奥,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門狭园,熙熙樓的掌柜王于貴愁眉苦臉地迎上來读处,“玉大人,你說我怎么就攤上這事唱矛》2眨” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵绎谦,是天一觀的道長管闷。 經(jīng)常有香客問我,道長窃肠,這世上最難降的妖魔是什么包个? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮冤留,結(jié)果婚禮上碧囊,老公的妹妹穿的比我還像新娘。我一直安慰自己纤怒,他們只是感情好糯而,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著泊窘,像睡著了一般熄驼。 火紅的嫁衣襯著肌膚如雪像寒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天谜洽,我揣著相機與錄音萝映,去河邊找鬼。 笑死阐虚,一個胖子當著我的面吹牛序臂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播实束,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼奥秆,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了咸灿?” 一聲冷哼從身側(cè)響起构订,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎避矢,沒想到半個月后悼瘾,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡审胸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年亥宿,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片砂沛。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡烫扼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出碍庵,到底是詐尸還是另有隱情映企,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布静浴,位于F島的核電站堰氓,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏苹享。R本人自食惡果不足惜双絮,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望富稻。 院中可真熱鬧,春花似錦白胀、人聲如沸椭赋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽哪怔。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間认境,已是汗流浹背胚委。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留叉信,地道東北人亩冬。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像硼身,于是被迫代替她去往敵國和親硅急。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容