HttpServletResponse.setStatus()只工作一次,当再次调用时什么都不做-在Java 8/Tom



我有一个在Tomcat9下运行的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状态就不能再更改了。然而,通过HttpServlet响应#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: 505505HTTP状态。就好像第二个setStatus((调用根本不存在。

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

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

在问题服务器上的上述servlet中,response.isCommitted()的返回值为false:在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;
}

最新更新