【问题标题】:How to send response without reading entire request?如何在不阅读整个请求的情况下发送响应?
【发布时间】:2016-02-01 09:54:08
【问题描述】:

我正在创建基于 Tomcat Servlets 和 NIO 的服务。输入时有很大的 XML 请求(~100 MB),通过 HTML POST 方法发送。我只想流式传输前 8 KiB,然后立即向客户端发送响应。

public class A extends HttpServlet {
    @Override
    protected void service(HttpServletRequest rq, HttpServletResponse rs) {
        byte[] buffer = new byte[1024*8];
        try {
            rq.getInputStream().read(buffer);
            rs.setContentType("text/plain");
            rs.getOutputStream().write("Some Response".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } 
     }
}

当我尝试发送小请求(内容中的几行)时没有问题,套接字正常工作。

2016-02-01 10:44:52 Http11NioProtocol [DEBUG] 套接字: [org.apache.tomcat.util.net.NioEndpoint$KeyAttachment@74f19fed:org.apache.tomcat.util.net.NioChannel@c478210:java.nio.channels.SocketChannel[已连接 本地=/0:0:0:0:0:0:0:1:8080 远程=/0:0:0:0:0:0:0:1:63943]],状态 输入:[OPEN_READ],输出:[OPEN]

但是,如果我尝试发送更大的请求(超过 100 MB),客户端没有响应。

2016-02-01 10:48:42 Http11NioProtocol [DEBUG] 套接字: [org.apache.tomcat.util.net.NioEndpoint$KeyAttachment@2b36c88f:org.apache.tomcat.util.net.NioChannel@25f12241:java.nio.channels.SocketChannel[已连接 本地=/0:0:0:0:0:0:0:1:8080 远程=/0:0:0:0:0:0:0:1:64079]],状态 输入:[OPEN_READ],声明输出:[CLOSED]

2016-02-01 10:48:42 LimitLatch [DEBUG] 计数 向下[http-nio-8080-exec-3] latch=1

在我读取整个输入流请求之前,Tomcat 不想打开套接字(状态输出:CLOSED)。

是否可以在不读取整个请求的情况下向客户端发送响应?根据规范,我能够在请求的前 8 KiB 中找到我感兴趣的信息。

【问题讨论】:

  • 你的代码只读取了第一个 8KiB
  • 是的,你是对的,我的错:)

标签: java tomcat7 nio servlet-3.0


【解决方案1】:

您的代码只读取了请求的一部分,

您可以使用此方法将 Stream 转换为 String

private static String convertStreamToString(InputStream is) throws IOException{
        int i = 0;
        byte[] buff = new byte[1024];
        StringBuilder sb = new StringBuilder();
        while (i != -1) {            
            i = is.read(buff);
            if(i != -1){
            sb.append(new String(buff,0,i));
            }
        }
        return sb.toString();
    }

所以,在你的代码中它将是

public class A extends HttpServlet {
    @Override
    protected void service(HttpServletRequest rq, HttpServletResponse rs) {

        try {
            String response = convertStreamToString(rq.getInputStream());   
            rs.getOutputStream().write(response.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } 
     }
     private static String convertStreamToString(InputStream is) throws IOException{
        int i = 0;
        byte[] buff = new byte[1024];
        StringBuilder sb = new StringBuilder();
        while (i != -1) {            
            i = is.read(buff);
            if(i != -1){
                sb.append(new String(buff,0,i));
            }
        }
        return sb.toString();
    }

}

或者您可以使用Scanner 直接将您的流转换为字符串

    Scanner scanner = new Scanner(inputStream);
    StringBuilder sb = new StringBuilder();
    while (scanner.hasNext()) {            
        sb.append(scanner.next());
    }

所以,在你的代码中应该是

public class A extends HttpServlet {
    @Override
    protected void service(HttpServletRequest rq, HttpServletResponse rs) {

        try {
             Scanner scanner = new Scanner(rq.getInputStream());
             StringBuilder sb = new StringBuilder();
             while (scanner.hasNext()) {            
                 sb.append(scanner.next());
             }
            rs.getOutputStream().write(sb.toString().getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } 
     }

}

这段代码

byte[] buffer = new byte[1024*8];
rq.getInputStream().read(buffer);

只读取1024字节的请求并将其存储到缓冲区数组(1024字节),方法read将返回读取了多少字节,因为根本不会读取1024的字节,如果请求只发送200字节,824字节将是无用的。所以,如果请求只发送 200 个字节

int x = rq.getInputStream().read(buffer);

这个 x 将是 200, 所以要完整阅读,你需要循环

// integer to read
int bytesRead = 0;
// loop until bytesRead is -1 (end of request), -1 means there are no bytes to read, so it will read until there are no bytes to read
while(bytesRead != -1){
    bytesRead = rq.getInputStream().read(buffer);
    if(bytesRead != -1){
    // process the bytes here , but only process bytes from 0 to bytesRead
     }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多