如何将生成的缓冲图像从 Servlet 传递到响应?

How to pass the generated Buffered image from Servlet to the response?

在我的 Servlet 中,我生成了一个 BufferedImage:

BufferedImage bgImage = createImage();

然后保存:

saveImage(bgImg, getImageSaveDir() + IMAGE_NAME);

之后我想 return 将其响应显示在浏览器中。

我尝试将图像发送到响应:

File imageFile = new File(getImageSaveDir() + IMAGE_NAME);
response.setContentType("image/png");
BufferedImage bufferedImg = ImageIO.read(imageFile);
ServletOutputStream out = response.getOutputStream();
ImageIO.write(bufferedImg, "png", out);
out.close();
} catch (Exception ex) {
  ex.printStackTrace();
}

但是我收到一个异常:

ClientAbortException:  java.net.SocketException: Broken pipe
    at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:369)
    at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:448)
    at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:318)
    at org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:296)
    at org.apache.catalina.connector.CoyoteOutputStream.flush(CoyoteOutputStream.java:98)
    at javax.imageio.stream.FileCacheImageOutputStream.close(FileCacheImageOutputStream.java:238)
    at javax.imageio.ImageIO.write(ImageIO.java:1580)
    at tv.clever.xml.TeamImageProcessor.process(TeamImageProcessor.java:157)
    at tv.clever.api.ApiServlet.doProcessing(ApiServlet.java:458)
    at tv.clever.api.ApiServlet.process(ApiServlet.java:219)
    at tv.clever.api.ApiServlet.doPost(ApiServlet.java:98)
    at tv.clever.api.ApiServlet.doGet(ApiServlet.java:86)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:723)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:198)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at tv.clever.utils.messageresource.UTF8EncodingFilter.doFilter(UTF8EncodingFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at tv.clever.utils.security.URLFilter.doFilter(URLFilter.java:50)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at tv.clever.utils.security.CrossScriptingFilter.doFilter(CrossScriptingFilter.java:38)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:470)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:861)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:620)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.net.SocketException: Broken pipe
    at java.net.SocketOutputStream.socketWrite0(Native Method)
    at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:113)
    at java.net.SocketOutputStream.write(SocketOutputStream.java:159)
    at org.apache.coyote.http11.InternalOutputBuffer.realWriteBytes(InternalOutputBuffer.java:761)
    at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:448)
    at org.apache.tomcat.util.buf.ByteChunk.append(ByteChunk.java:363)
    at org.apache.coyote.http11.InternalOutputBuffer$OutputStreamOutputBuffer.doWrite(InternalOutputBuffer.java:785)
    at org.apache.coyote.http11.filters.ChunkedOutputFilter.doWrite(ChunkedOutputFilter.java:124)
    at org.apache.coyote.http11.InternalOutputBuffer.doWrite(InternalOutputBuffer.java:598)
    at org.apache.coyote.Response.doWrite(Response.java:533)
    at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:364)
    ... 39 more

What is the best way to pass the generated Buffered image from Servlet to the response and display it in the browser?

我试过这个:

BufferedImage originalImage = ImageIO.read(new File(getImageSaveDir() + IMAGE_NAME));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(originalImage, "png", baos);
baos.flush();
byte[] imageInByte = baos.toByteArray();
baos.close();
response.setContentType("image/png");
response.setContentLength(imageInByte.length);
ServletOutputStream servletoutputstream = response.getOutputStream();
servletoutputstream.write(imageInByte);
servletoutputstream.flush();

现在异常没有出现,但是代码还是不行:(

请参阅下面的 org.apache.catalina.connector.OutputBuffer.realWriteBytes 代码,这是出现异常的地方。

    // If we really have something to write
    if (cnt > 0) {
        // real write to the adapter
        outputChunk.setBytes(buf, off, cnt);
        try {
            coyoteResponse.doWrite(outputChunk);
        } catch (IOException e) {
            // An IOException on a write is almost always due to
            // the remote client aborting the request. Wrap this
            // so that it can be handled better by the error dispatcher.
            throw new ClientAbortException(e);
        }
    }

现在请注意异常中的注释

An IOException on a write is almost always due to the remote client aborting the request.

在我看来,您的浏览器和服务器之间似乎存在连接问题。可能连接断开了。

现在可能有多种原因导致 HTTP 连接断开,例如:

  • 请求响应时间过长,因此网络服务器根据 HTTP 超时使请求超时。
  • 来自客户端的请求被终止。
  • 您发送了客户端无法理解的内容或不可接受的 MIME 类型,因此当 Web 服务器尝试提交响应时出现错误。

在 Weblogic 的情况下,如果我从浏览器启动服务器事务,然后在服务器响应之前关闭浏览器,那么在提交响应时,WL 将抛出以下异常。
在您的情况下,根异常也是 IOException 但它被包装到 ClientAbortException 以便在日志控制台上有意义。

java.io.IOException: An established connection was aborted by the software in your host machine
        at sun.nio.ch.SocketDispatcher.write0(Native Method)
        at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:51)
        at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93)
        at sun.nio.ch.IOUtil.write(IOUtil.java:65)
        at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:487)

因此,您可能想要: