首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Struts Token 機制防重複提交:完整實作與原理深度解析

     編輯:Java 相關知識

表單重複提交是 Web 應用常見問題:使用者連點提交按鈕、重整結果頁、瀏覽器後退重送。Struts 內建 Token 機制 (同步器 Token 模式) 以 Session 端唯一 Token 驗證請求唯一性,有效防範重複提交。

Token 機制核心流程

  1. 產生 Token:saveToken(request) 在 Session 生成唯一 Token,同步寫入表單隱藏欄位
  2. 提交攜帶 Token:表單送出時自動包含 org.apache.struts.taglib.html.TOKEN
  3. 驗證 Token:isTokenValid(request) 比對 Session 與請求 Token
  4. 消耗 Token:resetToken(request) 移除 Session Token,下次請求將失效
  5. 重新產生:驗證失敗或業務錯誤時 saveToken(request) 重新發行

完整實作範例

1. 準備動作:產生 Token 並導向輸入頁

public class PrepareInsertAction extends Action {
    public ActionForward execute(ActionMapping mapping, ActionForm form,
                                 HttpServletRequest request, HttpServletResponse response) {
        saveToken(request); // 關鍵:產生 Token 存入 Session
        return mapping.findForward("insertTokenPage");
    }
}

2. 輸入頁面 (tokenInsert.jsp) 自動嵌入 Token

<html:form action="/insert" method="post">
    <bean:message key="label.name"/> <html:text property="name"/><br/>
    <bean:message key="label.phone"/> <html:text property="phone"/><br/>
    <bean:message key="label.address"/> <html:text property="address"/><br/>
    <html:submit><bean:message key="button.submit"/></html:submit>
    <html:reset><bean:message key="button.reset"/></html:reset>
</html:form>
<html:errors/> <!-- 顯示驗證錯誤 -->

<html:form> 標籤自動輸出:<input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="a1b2c3d4..."/>

3. 處理動作:驗證與消耗 Token

public class InsertAction extends Action {
    public ActionForward execute(ActionMapping mapping, ActionForm form,
                                 HttpServletRequest request, HttpServletResponse response) 
            throws Exception {
        
        // 1. 驗證 Token
        if (!isTokenValid(request)) {
            // 重複提交:記錄錯誤、重新產生 Token、返回輸入頁
            ActionErrors errors = new ActionErrors();
            errors.add("token", new ActionError("error.invalid.token"));
            saveErrors(request, errors);
            saveToken(request); // 重新發行,允許使用者再次嘗試
            return new ActionForward(mapping.getInput());
        }
        
        // 2. 首次提交:消耗 Token,執行業務邏輯
        resetToken(request); // 關鍵:移除 Token,防止再次提交
        
        ModifyForm mf = (ModifyForm) form;
        int result = new ListBean().add(mf);
        
        if (result == 1) {
            return mapping.findForward("success");
        } else {
            saveToken(request); // 業務失敗時重新發行
            return mapping.findForward("error");
        }
    }
}

4. struts-config.xml 關鍵配置

<action-mappings>
    <!-- 步驟 1:準備頁面,產生 Token -->
    <action path="/prepareInsert" 
            type="com.example.action.PrepareInsertAction" />
    
    <!-- 步驟 2:處理提交,驗證 Token -->
    <action path="/insert"
            type="com.example.action.InsertAction"
            name="modifyForm"
            scope="request"
            input="/tokenInsert.jsp"  <!-- 驗證失敗返回頁面 -->
            attribute="modifyForm">
    </action>
</action-mappings>

<global-forwards>
    <forward name="insertTokenPage" path="/tokenInsert.jsp"/>
</global-forwards>

<message-resources parameter="ApplicationResources"/>

5. ApplicationResources.properties 錯誤訊息

error.invalid.token=重複提交偵測,請勿重複送出表單
label.name=姓名
label.phone=電話
label.address=地址
button.submit=送出
button.reset=重置

Token 原理深度剖析

// Action 類別核心方法 (Struts 1.3 源碼簡化)
protected void saveToken(HttpServletRequest request) {
    HttpSession session = request.getSession();
    String token = UUID.randomUUID().toString(); // 實際使用更複雜的生成演算法
    session.setAttribute("org.apache.struts.action.TOKEN", token);
}

protected boolean isTokenValid(HttpServletRequest request) {
    String sessionToken = (String) request.getSession().getAttribute(TOKEN_KEY);
    String requestToken = request.getParameter(TOKEN_KEY);
    return sessionToken != null && sessionToken.equals(requestToken);
}

protected void resetToken(HttpServletRequest request) {
    request.getSession().removeAttribute(TOKEN_KEY);
}

進階場景與注意事項

Struts 2 對應機制

Struts 2 使用 TokenInterceptor (預設堆疊不啟用),配置方式:

<action name="insert" class="com.example.InsertAction">
    <interceptor-ref name="defaultStack"/>
    <interceptor-ref name="token"/> <!-- 加入 token 攔截器 -->
    <result name="invalid.token">/tokenError.jsp</result>
    <result name="success">/success.jsp</result>
</action>

JSP 中:<s:token/> 自動生成隱藏欄位。

結語

Struts Token 機制以「產生→驗證→消耗→重新產生」四步驟,簡單有效解決重複提交。關鍵在於:準備頁面必須先 saveToken(),處理頁面必須 isTokenValid() 後 resetToken(),異常分支要重新 saveToken()。掌握此模式,可輕鬆移植至任何 MVC 框架或自行實作。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
場景處理策略
多標籤頁操作Token 綁定 Session,會互相干擾。改用 TokenProcessor 自訂 Token 範圍 (請求/會話/表單)
AJAX 非同步提交回應 JSON 包含新 Token,前端更新隱藏欄位
檔案上傳大表單驗證前先 saveToken(),避免上傳超時導致 Token 過期
集群環境Session 複製或集中式 Session (Redis) 確保 Token 跨節點一致
巢狀表單/多表單頁面每個表單獨立 Token,使用 formBean 隔離