如何正确读取http请求?

How to read http request properly?

如何使用InputStream读取HTTP请求?我以前是这样读的:

InputStream in = address.openStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder result = new StringBuilder();
String line;
while((line = reader.readLine()) != null) {
    result.append(line);
}
System.out.println(result.toString()); 

但是 reader.readLine() 可能会被阻塞,因为无法保证一定会到达 null 行。当然我可以读取 Content-Length header 然后循环读取请求:

for (int i = 0; i < contentLength; i++) {
                int a = br.read();
                body.append((char) a);
    }

但是如果Content-Length设置太大(我猜它可以手动设置目的),br.read()将被阻止。 我尝试像这样直接从 InputStream 读取字节:

byte[] bytes = getBytes(is);

public static byte[] getBytes(InputStream is) throws IOException {

            int len;
            int size = 1024;
            byte[] buf;

            if (is instanceof ByteArrayInputStream) {
              size = is.available();
              buf = new byte[size];
              len = is.read(buf, 0, size);
            } else {
              ByteArrayOutputStream bos = new ByteArrayOutputStream();
              buf = new byte[size];
              while ((len = is.read(buf, 0, size)) != -1)
                bos.write(buf, 0, len);
              buf = bos.toByteArray();
            }
            return buf;
          }

但它会永远等待。做什么?

创建一个扩展 HttpServletRequestWrapper 的请求包装器,它将覆盖 getInputStream() ,后者又 return ServletInputStream ,后者具有安全读取方法。试试看

如果您正在实施 HTTP 服务器,您应该根据 HTTP 规范检测请求的结束。维基 - https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol

首先,您应该阅读请求行,它始终是一行。 然后读取所有请求headers。你阅读它们直到你有一个空行(即两个行结尾 - <CR><LF>)。

有了状态行和 headers 之后,您应该决定是否需要阅读 body 或不需要,因为并非所有请求都可能有 body - summary table

然后,如果您需要 body,您应该解析您的 headers(您已经获得)并获得 Content-Length。如果是 - 只需从流中读取指定的字节数。 当缺少 Content-Length 时,长度以其他方式确定。分块传输编码使用大小为 0 的块来标记内容的结尾。没有 Content-Length 的身份编码会读取内容,直到套接字关闭。