用戶雙擊提交按鈕、瀏覽器刷新/後退導致的表單重複提交,可能造成重複訂單、重複扣款等嚴重業務問題。本文講解基於 Session Token 的服務端幂等性校驗方案。
<%@ page contentType="text/html;charset=GB2312" %>
<html><head><title>提交頁面</title></head><body>
<%
// 生成 Token 存入 Session
String token = UUID.randomUUID().toString();
session.setAttribute("submitToken", token);
%>
<form action="ServerSubmit.jsp" method="post">
<input type="hidden" name="token" value="<%=token%>" />
<input type="checkbox" name="check_1" checked="true" />人在江湖
<input type="submit" name="submitok" value="提交" />
</form>
</body></html>
<%@ page contentType="text/html;charset=GB2312" %>
<html><head><title>服務器端程序</title></head><body>
<%
String clientToken = request.getParameter("token");
String serverToken = (String) session.getAttribute("submitToken");
if (serverToken == null || !serverToken.equals(clientToken)) {
out.println("重複提交或無效請求!");
} else {
// 業務邏輯處理...
out.println("正常業務處理完成!");
// 關鍵:處理後立即移除 Token,防止重複
session.removeAttribute("submitToken");
}
%>
</body></html>
@WebFilter("/*")
public class TokenFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
if ("POST".equalsIgnoreCase(request.getMethod())) {
String token = request.getParameter("token");
String sessionToken = (String) request.getSession().getAttribute("submitToken");
if (sessionToken == null || !sessionToken.equals(token)) {
response.sendRedirect("duplicate_submit.jsp");
return;
}
request.getSession().removeAttribute("submitToken");
}
chain.doFilter(req, resp);
}
}