You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

启用HTTPS后Tomcat 10出现浏览器返回按钮表单重复提交问题

解决Tomcat启用HTTPS后返回按钮触发表单重复提交(ERR_CACHE_MISS)的问题

问题根源

启用HTTPS后,浏览器对POST请求的缓存策略会更严格,同时Tomcat的HTTPS连接器默认可能添加no-cache类响应头,导致POST提交后的页面无法被浏览器缓存。点击返回按钮时,浏览器无法从缓存加载上一页,只能重新发起POST请求,从而触发"Confirm Form Resubmission"提示。

解决方案

1. 采用PRG模式(POST-Redirect-GET)

这是解决表单重复提交最标准的方案:表单提交后,服务器处理完POST请求,不直接转发到结果页,而是通过重定向(sendRedirect)跳转到GET请求的页面。这样浏览器历史记录里保存的是GET请求,点击返回时只会加载这个GET页面,不会触发POST重提交。

示例代码(Servlet处理POST):

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // 处理表单提交逻辑,比如保存数据
    saveFormData(request);
    
    // 重定向到结果页(GET请求)
    response.sendRedirect(request.getContextPath() + "/success.jsp");
}

2. 调整Tomcat的响应缓存头配置

如果某些静态结果页需要被缓存,可以通过过滤器或页面设置修改响应头,允许浏览器缓存HTTPS下的页面:

  • 通过Web Filter设置:
    在web.xml中添加过滤器:
<filter>
    <filter-name>CacheControlFilter</filter-name>
    <filter-class>com.yourpackage.CacheControlFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CacheControlFilter</filter-name>
    <url-pattern>/success/*</url-pattern> <!-- 匹配需要缓存的页面路径 -->
</filter-mapping>

过滤器实现:

public class CacheControlFilter implements Filter {
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        // 设置缓存策略:允许公开缓存,有效期1小时
        response.setHeader("Cache-Control", "public, max-age=3600");
        response.setHeader("Expires", String.valueOf(System.currentTimeMillis() + 3600 * 1000));
        chain.doFilter(req, res);
    }
}
  • 直接在JSP页面设置:
    在需要缓存的JSP头部添加:
<%
    response.setHeader("Cache-Control", "public, max-age=3600");
    response.setHeader("Expires", String.valueOf(System.currentTimeMillis() + 3600 * 1000));
%>

3. 补充:添加表单Token防止重复提交(可选)

如果担心用户手动刷新页面导致重复提交,可以在表单中添加唯一Token,服务器验证Token有效性:

<form method="post" action="submit">
    <input type="hidden" name="token" value="${sessionScope.token}">
    <!-- 其他表单字段 -->
    <button type="submit">提交</button>
</form>

Servlet生成和验证Token:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // 生成唯一Token并存入Session
    String token = UUID.randomUUID().toString();
    request.getSession().setAttribute("token", token);
    request.getRequestDispatcher("form.jsp").forward(request, response);
}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String requestToken = request.getParameter("token");
    String sessionToken = (String) request.getSession().getAttribute("token");
    
    if (requestToken != null && requestToken.equals(sessionToken)) {
        // 处理表单提交
        saveFormData(request);
        // 移除Token,防止重复使用
        request.getSession().removeAttribute("token");
        response.sendRedirect("success.jsp");
    } else {
        // 重复提交,返回错误提示
        response.sendRedirect("error.jsp");
    }
}

关键注意点

  • PRG模式是解决返回按钮问题的核心,其他方案仅作为补充。
  • HTTPS下不要强制缓存敏感页面,避免安全风险。

内容的提问来源于stack exchange,提问作者Feng Zhang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 20:52:23