java - HttpServletResponse.setStatus() 工作一次,再次调用时什么也不做 - 在 Java 8/Tomcat 9.0.0 和 Java 10/Tomcat 9.0.8 之间改变?
问题描述
我有一个在 Tomcat 9 下运行的 Java servlet,作为正常流程的一部分,它会调用HttpServletResponse#setStatus()
几次。
在使用 Java 8(1.8.0u144,Tomcat 报告为 )的 Tomcat 9.0.0.M26 上运行时1.8.0_144-b01
,它可以正常工作。
在 Tomcat 9.0.8.0 和 Java 10.0.1 上运行时(10.0.1+10
Tomcat报告为改变了。但是,通过 HttpServletResponse#setHeader() 发送到客户端的其他标头似乎不受此影响;即使在 setStatus() 不再执行任何操作之后,setHeader() 也会成功添加标题。没有发送可能导致 HTTP 标头终止的中间输出数据。
这是一个最小的工作示例:
package org.example;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/HttpResponseStatusTestServlet")
public class HttpResponseStatusTestServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getWriter().append("Testing ");
response.setStatus(505);
response.setStatus(506);
response.getWriter()
.append("Served at: ")
.append(request.getContextPath())
.append(" with: ")
.append(Integer.toString(response.getStatus()));
}
}
调用此 servlet 时,我希望返回字符串,因为在调用Testing Served at: ... with: 506
之前设置的最后一个 HTTP 状态是. 返回给客户端的 HTTP 状态码也应该是.getStatus()
506
506
但是,我最终得到的是Testing Served at: ... with: 505
一个505
HTTP 状态。就像第二个 setStatus() 调用甚至不存在一样。
无论是否包含 setStatus() 调用之前的结果都是相同的(除了Testing
输出开头的存在response.getWriter().append("Testing ");
),因此它似乎与提前终止 HTTP 响应标头无关。
没有任何迹象表明我可以看到第二个 setStatus() 调用以任何方式失败,甚至它曾经存在过;似乎除了第一次调用 setStatus() 之外,在响应对象上调用 setStatus() 完全没有任何作用。
的返回值贯穿于有问题的服务器response.isCommitted()
上false
的上述 servlet:getWriter().append("Testing ");
调用后、setStatus(505)
调用后和setStatus(506)
调用后。
我意识到为同一个请求多次调用 setStatus() 可能有点不正统,但是:
- 鉴于它与 Tomcat 9.0.0 和 Java 8 完美配合,这真的不应该与 Tomcat 9.0.8 和 Java 10 一起使用吗?
- 与较新版本一起使用的等效项是什么?
使用通用的网络搜索引擎让我对正在发生的事情一无所知,而且我能够找到的文档并不表明 setStatus() 只能调用一次,也不能多次调用它。
解决方案
多次调用setStatus()
是不被禁止的,如果你查看 Tomcat 内部,你会发现有些地方可以多次更改状态(当然,如果它被禁止,你会得到一个例外)。
这是由 Tomcat 9.0.10 和 9.0.9 中修复的回归错误引起的,但不是 9.0.8(没有查看错误的引入位置,可能在 9.0.8 中)。
如果它已经设置为超过 399 的值,则基本上尝试更改状态代码没有任何效果,因为
if (this.status > 399) {
// Don't overwrite first recorded error status
return;
}
推荐阅读
- java - 如何在nodelist中将xml解析为java
- visual-studio - 关闭所有,但固定和这个?
- java - PowerMockito 验证永远不会调用静态方法
- grails - 如何通过模拟对象并期待一些预期结果来编写 Spock 单元测试
- corda - 我们应该如何升级一个由一个 DL 参与者拥有但有一个包含多个参与者的参与者列表的状态?
- ruby - 数组意外多重赋值
- continuous-integration - CircleCI:ESLint 在 CI 上返回退出代码 0 尽管测试失败
- javascript - 如果从数据库中获取的数据是!=“Detained”,如何调用函数
- javascript - Javascript - Firebase 子键
- c# - jQuery ajax 从代码隐藏中获取表格