HTTP请求报文格式
1. 结构:
[请求行]
[请求头]
[空行]
[请求体] (可选)
-
请求行:
方法 URI HTTP版本
常见方法:GET
(获取资源)、POST
(提交数据)、PUT
(替换资源)、DELETE
(删除资源)。
例如:GET /index.html HTTP/1.1
-
请求头:键值对形式,传递附加信息(如客户端信息、内容类型等)。
常见字段:Host: www.example.com
(目标域名,HTTP/1.1必需)User-Agent: Mozilla/5.0
(客户端信息)Accept: text/html
(客户端可接受的响应类型)Content-Type: application/json
(请求体类型,POST/PUT时使用)Content-Length: 27
(请求体的字节长度)
-
请求体:仅某些方法(如POST、PUT)携带,如提交表单或JSON数据。
2. 示例(GET请求):
http
GET /page.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
Accept: text/html
3. 示例(POST请求):
POST /login HTTP/1.1
Host: www.example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 29
username=test&password=1234
4. 判断请求头结束的方式
1. 无消息体的请求(如GET、HEAD、DELETE等)
- 结束标志:请求头(Headers)之后紧跟两个连续的CRLF(即空行),此时请求结束。
- 示例:
GET /index.html HTTP/1.1\r\n Host: example.com\r\n \r\n
2. 有消息体的请求(如POST、PUT等)
对于包含消息体的请求,需通过以下方式确定结束:
a. 使用 Content-Length
头部
- 作用:明确指定消息体的字节长度。
- 判断方式:服务端读取完指定长度的字节后,视为请求结束。
- 示例:
POST /upload HTTP/1.1\r\n Content-Length: 1234\r\n \r\n <1234字节的数据>
b. 使用分块传输编码(Transfer-Encoding: chunked
)
- 作用:将消息体分块传输,适用于动态生成内容或无法预知内容大小的情况。
- 判断方式:
- 每个分块以十六进制长度开头,后跟CRLF和数据块。
- 以长度标识为
0
的块表示结束,后跟最终的CRLF。
- 示例:
POST /data HTTP/1.1\r\n Transfer-Encoding: chunked\r\n \r\n 5\r\n Hello\r\n 0\r\n \r\n
c. 无Content-Length
与Transfer-Encoding
的情况
- HTTP/1.0:无持久连接时,可能依赖客户端关闭连接判断结束(不推荐用于HTTP/1.1)。
- HTTP/1.1:规范要求必须明确指定长度或使用分块编码,否则服务器会返回
400 Bad Request
错误。
3. 其他注意事项
- Expect头处理:若请求包含
Expect: 100-continue
,服务端需先响应100 Continue
状态码,再按规则处理消息体。 - 协议版本差异:HTTP/1.1严格要求使用
Content-Length
或分块编码处理持久连接中的请求,而HTTP/1.0可能允许通过关闭连接判断结束。
总结流程图
开始接收请求
├─ 读取请求头直至空行(\r\n\r\n)
├─ 判断是否存在消息体?
│ ├─ 否 → 请求结束
│ └─ 是 → 检查头部:
│ ├─ 若有Content-Length → 读取指定字节数后结束
│ ├─ 若Transfer-Encoding: chunked → 解析分块直至遇到长度0块
│ └─ 无明确标识 → 按协议版本处理(HTTP/1.1返回错误,HTTP/1.0可能读取到连接关闭)
结束
HTTP响应报文格式
1. 结构:
[状态行]
[响应头]
[空行]
[响应体] (可选)
-
状态行:
HTTP版本 状态码 状态消息
常见状态码:200 OK
:成功404 Not Found
:资源未找到500 Internal Server Error
:服务器错误301 Moved Permanently
:永久重定向
-
响应头:提供服务器信息或资源元数据。
常见字段:Server: Apache/2.4
(服务器信息)Content-Type: text/html
(响应体类型)Content-Length: 1024
(响应体的字节长度)Set-Cookie: session=abc123
(设置Cookie)
-
响应体:请求资源的内容(如HTML、JSON、图片等)。
-
判断HTTP响应结束的方式:
-
Content-Length准则
- 当响应头包含
Content-Length
时,消息体需精确读取指定字节数 - 示例行为:
inputStream.read(body)
严格读取给定长度
- 当响应头包含
-
Chunked分块准则
- 当
Transfer-Encoding: chunked
时,循环读取格式为:[块大小]\r\n[块数据]\r\n
- 终止条件:读取到
0\r\n
表示所有分块传输完成
- 当
-
连接关闭准则
- 无上述头部且非持久连接时,持续读取直到
inputStream.read()
返回-1
- 无上述头部且非持久连接时,持续读取直到
// 伪代码演示HTTP响应结束判断
class HttpResponseParser {
void parseResponse(InputStream inputStream) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
Map<String, String> headers = new HashMap<>();
String line;
// 1. 解析响应头
while ((line = reader.readLine()) != null) {
if (line.isEmpty()) break; // 头部结束标记(空行)
if (line.contains(":")) {
String[] parts = line.split(":", 2);
headers.put(parts[0].trim().toLowerCase(), parts[1].trim());
}
}
// 2. 判断消息体结束规则
if (headers.containsKey("content-length")) {
// 情况1:通过Content-Length确定结束位置
int length = Integer.parseInt(headers.get("content-length"));
byte[] body = new byte[length];
inputStream.read(body); // 严格读取指定长度
processBody(body);
} else if ("chunked".equals(headers.get("transfer-encoding"))) {
// 情况2:通过分块编码判断结束
while (true) {
String chunkSizeLine = reader.readLine();
int chunkSize = Integer.parseInt(chunkSizeLine.split(";")[0], 16); // 解析16进制长度
if (chunkSize == 0) break; // 结束标记
byte[] chunk = new byte[chunkSize];
inputStream.read(chunk);
reader.readLine(); // 丢弃块结束的CRLF
processChunk(chunk);
}
} else {
// 情况3:持续读取直到流关闭(HTTP/1.0旧模式)
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int b;
while ((b = inputStream.read()) != -1) { // -1表示流结束
buffer.write(b);
}
processBody(buffer.toByteArray());
}
}
// 示例方法:处理完整消息体
void processBody(byte[] data) { /* ... */ }
// 示例方法:处理分块数据
void processChunk(byte[] chunk) { /* ... */ }
}
2. 示例(成功响应HTML):
http
HTTP/1.1 200 OK
Server: Nginx
Content-Type: text/html
Content-Length: 158
<html>
<head><title>示例页面</title></head>
<body>Welcome!</body>
</html>
3. 示例(错误响应):
http
HTTP/1.1 404 Not Found
Content-Type: text/plain
Content-Length: 15
Page not found.
4. 示例(JSON响应):
http
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 28
{"status": "success", "data": {}}
完整交互示例
客户端访问 https://www.example.com/index.html
:
- 请求:
http
GET /index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
Accept: text/html
- 响应:
http
HTTP/1.1 200 OK
Server: Apache/2.4
Content-Type: text/html
Content-Length: 1234
<!DOCTYPE html>
<html>...</html>
关键注意事项
- 空行分隔:头部和主体间必须有一个仅包含CRLF的空行。
- 方法区分:GET一般无请求体,POST/PUT通过
Content-Type
和Content-Length
指定请求体格式。 - 无状态协议:HTTP协议本身不保存状态,依赖Cookie/Session等机制。
- 扩展性:可通过自定义头部字段(如
Authorization: Bearer token
)实现扩展功能。
掌握HTTP报文格式能帮助理解Web开发、API设计和网络调试(如使用浏览器开发者工具或Fiddler抓包)。