如何正确读取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 的身份编码会读取内容,直到套接字关闭。
如何使用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 的身份编码会读取内容,直到套接字关闭。