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报告为1.8.0_144-b01 )在Tomcat 9.0.0.M26上运行时,这很好用。

当在带有Java 10.0.1的Tomcat 9.0.8.0上运行时(由Tomcat报告为10.0.1+10 ),似乎在响应对象上调用setStatus()实际上只会导致响应状态设置一次 ,之后HTTP状态无法再更改。 但是,通过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因为在getStatus()调用之前设置的最后一个HTTP状态是506 。 返回给客户端的HTTP状态代码同样应为506

但是,我最终得到的是Testing Served at: ... with: 505505 HTTP状态。 这就像第二个setStatus()调用甚至没有。

结果是相同的(除了输出开头是否存在Testing )是否response.getWriter().append("Testing "); 在包含setStatus()调用之前,它似乎不是关于提前终止的HTTP响应头。

在任何地方都没有迹象表明我可以看到第二个setStatus()调用以任何方式失败,甚至它曾经存在过; 似乎在第一次调用setStatus()之后的任何地方,在响应对象上调用setStatus()完全没有任何作用。

在有问题的服务器上的整个上述servlet中, response.isCommitted()的返回值为falsegetWriter().append("Testing "); 在调用setStatus(505)之后,调用setStatus(506)调用。

我意识到为同一个请求多次调用setStatus()可能会略显不正统,但是:

  • 这真的不适用于Tomcat 9.0.8和Java 10,因为它与Tomcat 9.0.0和Java 8完美配合吗?
  • 与更新版本一起使用的等价物是什么?

使用一个常见的网络搜索引擎让我不知道发生了什么,我能找到的文档并没有表明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; }