【问题标题】:Why I can still send data after the response is commited with "response.flushBuffer()"?为什么使用“response.flushBuffer()”提交响应后仍然可以发送数据?
【发布时间】:2015-12-15 14:53:36
【问题描述】:

我使用以下 REST 处理程序将文件传输到客户端。

故意打电话给response.flushBuffer(),希望我应该被阻止写入响应,因为它已经提交了。而且我希望客户不会收到完整的文件。

但整个文件仍会发送给客户端。并且不会抛出关于 Response Already Committed 的异常。

为什么?

我的代码:

@RestController
public class ChunkedTransferAPI {

    @Autowired
    ServletContext servletContext;

    @RequestMapping(value = "bootfile.efi", method = { RequestMethod.GET, RequestMethod.HEAD })
    public void doHttpBoot(HttpServletResponse response) {

        String filename = "/realbootfile.efi";
        try {
            ServletOutputStream output = response.getOutputStream();

            InputStream input = servletContext.getResourceAsStream(filename);
            BufferedInputStream bufferedInput = new BufferedInputStream(input);
            int datum = bufferedInput.read();
            while (datum != -1) {
                output.write(datum);
                datum = bufferedInput.read();
                response.flushBuffer(); // <======= HERE
            }
            //output.flush();
            output.close();

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

【问题讨论】:

  • 为什么不使用 Outputsteam 的其他替代方法:public void write(byte b[], int off, int len),这样您就可以随心所欲地写入数据
  • @SercanOzdemir 感谢您的提醒。我只是为了好玩而尝试。 :)

标签: java spring rest spring-mvc web


【解决方案1】:

当标头已发送时,响应被“提交”,这意味着无法兑现对响应标头的更改。它不会阻止您编写响应正文。

【讨论】:

  • 谢谢。我认为这是一个非常奇怪的设计。
  • 实际上,这是完全明智的。如果 API 没有这个“提交”特性,那么 Web 容器的 servlet 堆栈将需要缓冲整个响应体,直到……以防 servlet 决定更改标头字段。
  • 我认为这个intentionally 引入了响应头和正文不一致的可能性。也许最好在调用response.flushBuffer() 时关闭整个响应。无论如何,先刷新标题然后再刷新正文有什么意义?
  • 再想一想,我同意这是必要的。因为headers must be sent before body,通过允许在正文之前发送标头,我们不需要缓冲可能巨大的响应正文,直到首先发送标头。所以我认为这不是因为servlet may decided to change a header,而是因为the precedence of header to body使它成为to send potentially huge response within limited buffer的唯一途径。
  • 我认为这可能与HTTP chunked transfer有关。由于首先发送 HTTP 标头,因此无法在标头中包含 Content-Length,因为内容长度尚未确定。我们必须使用Transfer Encoding 来表明这一点。 (en.wikipedia.org/wiki/Chunked_transfer_encoding)
猜你喜欢
  • 2021-07-21
  • 1970-01-01
  • 2021-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多