HTTP 请求报文详解

概述

HTTP (Hypertext Transfer Protocol,超文本传输协议) 是用于在网上传输数据的应用层协议。HTTP 采用请求-响应模型,其中客户端发送 HTTP 请求报文到服务器,服务器返回 HTTP 响应报文。本文档详细介绍 HTTP 请求报文的结构、各部分组成及其作用。

HTTP 请求报文的整体结构

一个完整的 HTTP 请求报文由以下四个部分组成:

复制代码
请求行 (Request Line)
请求头字段 (Header Fields)
空行 (Empty Line)
请求体 (Request Body) [可选]

结构示意图

复制代码
POST /users HTTP/1.1                          ← 请求行
Host: example.com                              ← 请求头字段
Content-Type: application/json                 ← 请求头字段
Content-Length: 49                             ← 请求头字段
Authorization: Bearer token123                 ← 请求头字段
                                               ← 空行
{"name": "John", "email": "john@example.com"}  ← 请求体

第一部分: 请求行 (Request Line)

定义

请求行是 HTTP 请求报文的第一行,包含三个关键信息,用单个空格分隔。

格式

复制代码
<方法> <请求目标> <协议版本>

组成部分

1. HTTP 方法 (Method)

HTTP 方法指示对资源要执行的操作类型。

常用方法及作用:

方法 作用 安全性 幂等性 可缓存
GET 获取资源
HEAD 获取资源元数据(不返回响应体)
POST 提交数据/创建资源 条件可缓存
PUT 更新/替换资源
DELETE 删除资源
PATCH 部分更新资源
OPTIONS 获取服务器支持的方法
CONNECT 建立隧道连接(用于代理)
TRACE 回显请求(用于调试)

重要特性说明:

  • 安全方法 (Safe Methods): 不会修改服务器状态的方法

  • 幂等方法 (Idempotent Methods): 多次执行相同请求产生相同效果的方法

  • 可缓存方法 (Cacheable Methods): 响应可以被缓存的方法

示例:

复制代码
GET /api/users HTTP/1.1
POST /api/users HTTP/1.1
PUT /api/users/123 HTTP/1.1
DELETE /api/users/123 HTTP/1.1
2. 请求目标 (Request Target)

请求目标指定要访问的资源,有四种形式:

a) 源形式 (Origin Form) - 最常用
复制代码
GET /path/to/resource?query=value HTTP/1.1
  • 包含绝对路径和可选的查询字符串

  • 用于 GET、POST、HEAD、OPTIONS 等方法

  • 需要配合 Host 头字段使用

b) 绝对形式 (Absolute Form)
复制代码
GET https://example.com/path HTTP/1.1
  • 包含完整的 URL

  • 主要用于代理服务器

c) 授权形式 (Authority Form)
复制代码
CONNECT example.com:443 HTTP/1.1
  • 仅包含主机和端口

  • 专用于 CONNECT 方法建立隧道

d) 星号形式 (Asterisk Form)
复制代码
OPTIONS * HTTP/1.1
  • 使用 * 表示整个服务器

  • 仅用于 OPTIONS 方法

3. 协议版本 (Protocol Version)

指定使用的 HTTP 协议版本。

主要版本:

  • HTTP/0.9 (1991) - 已废弃

  • HTTP/1.0 (1996) - 已过时

  • HTTP/1.1 (1997) - 当前标准,广泛使用

  • HTTP/2 (2015) - 二进制协议,支持多路复用

  • HTTP/3 (2022) - 基于 QUIC/UDP 的最新版本

示例:

复制代码
GET /index.html HTTP/1.1

第二部分: 请求头字段 (Header Fields)

定义

请求头字段提供关于请求、客户端和请求体的附加信息。每个头字段由字段名、冒号、字段值组成。

格式

复制代码
字段名: 字段值

特点

  • 字段名不区分大小写

  • 字段值通常不能包含 CRLF

  • 多个值可用逗号分隔

  • HTTP/1.1 中除了 Host 外其他都是可选的

分类和常用头字段

1. 通用头字段 (General Headers)

适用于请求和响应的头字段。

头字段 作用 示例
Date 消息创建的日期和时间 Date: Mon, 27 Jul 2009 12:28:53 GMT
Connection 控制连接管理 Connection: keep-aliveConnection: close
Cache-Control 缓存指令 Cache-Control: no-cache, no-store
Pragma HTTP/1.0 的缓存控制(已过时) Pragma: no-cache
Trailer 指示消息尾部包含哪些头字段 Trailer: Expires
Transfer-Encoding 传输编码方式 Transfer-Encoding: chunked
Upgrade 请求升级到另一个协议 Upgrade: websocket
Via 代理服务器信息 Via: 1.1 proxy.example.com
2. 请求头字段 (Request Headers)

特定于请求的头字段。

头字段 作用 示例
Host 目标服务器的主机名和端口(HTTP/1.1 必需) Host: www.example.com
User-Agent 客户端软件信息 User-Agent: Mozilla/5.0
Accept 客户端可接受的媒体类型 Accept: text/html, application/json
Accept-Encoding 客户端支持的内容编码 Accept-Encoding: gzip, deflate, br
Accept-Language 客户端偏好的语言 Accept-Language: zh-CN, en;q=0.9
Accept-Charset 客户端支持的字符集(已废弃) Accept-Charset: utf-8
Referer 请求来源页面的 URL Referer: https://google.com
From 用户的电子邮件地址 From: user@example.com
If-Modified-Since 条件请求,仅当资源修改后才返回 If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT
If-None-Match 条件请求,基于 ETag If-None-Match: "686897696a7c876b7e"
If-Match 条件请求,仅当 ETag 匹配时处理 If-Match: "686897696a7c876b7e"
If-Unmodified-Since 条件请求,仅当资源未修改时处理 If-Unmodified-Since: Wed, 21 Oct 2015 07:28:00 GMT
If-Range 部分请求的条件 If-Range: "686897696a7c876b7e"
Range 请求资源的部分内容 Range: bytes=0-1023
Max-Forwards 请求可经过的最大代理数 Max-Forwards: 10
TE 客户端可接受的传输编码 TE: trailers, deflate
Expect 客户端期望的服务器行为 Expect: 100-continue
3. 实体头字段 (Entity/Representation Headers)

描述请求体的元数据。

头字段 作用 示例
Content-Type 请求体的媒体类型 Content-Type: application/json; charset=utf-8
Content-Length 请求体的字节长度 Content-Length: 1234
Content-Encoding 请求体的编码方式 Content-Encoding: gzip
Content-Language 请求体的自然语言 Content-Language: zh-CN
Content-Location 请求体的备用位置 Content-Location: /documents/foo.json
Content-Range 部分内容的位置信息 Content-Range: bytes 200-1000/5000
4. 认证和授权头字段
头字段 作用 示例
Authorization 客户端的认证凭证 Authorization: Bearer eyJhbGc...
Proxy-Authorization 代理服务器的认证凭证 Proxy-Authorization: Basic dXNlcjpwYXNz
Cookie 发送 Cookie 到服务器 Cookie: sessionId=abc123; theme=dark
5. 常见的自定义/扩展头字段
头字段 作用 示例
X-Requested-With 标识 AJAX 请求 X-Requested-With: XMLHttpRequest
X-Forwarded-For 客户端真实 IP(通过代理) X-Forwarded-For: 203.0.113.195
X-Forwarded-Host 客户端请求的原始主机 X-Forwarded-Host: example.com
X-Forwarded-Proto 客户端使用的协议 X-Forwarded-Proto: https
Origin 请求的源(用于 CORS) Origin: https://example.com
Access-Control-Request-Method CORS 预检请求的方法 Access-Control-Request-Method: POST
Access-Control-Request-Headers CORS 预检请求的头字段 Access-Control-Request-Headers: Content-Type

完整示例

复制代码
GET /api/users?page=1&limit=10 HTTP/1.1
Host: api.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Connection: keep-alive
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Referer: https://example.com/dashboard
Cookie: sessionId=abc123; theme=dark
Cache-Control: no-cache

第三部分: 空行 (Empty Line)

定义

空行是一个 CRLF (回车换行符,\r\n),用于分隔请求头和请求体。

作用

  • 标记请求头部分的结束

  • 告诉服务器元数据已完成,后续内容为请求体

  • HTTP/1.1 中必须存在,即使没有请求体

重要性

如果缺少空行:

  • 服务器可能将请求体的内容误认为是头字段

  • 可能导致请求解析错误

  • 通常会返回 400 Bad Request 错误

示例

复制代码
POST /api/data HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: 27
                              ← 这里是空行 (CRLF)
{"key":"value","id":123}      ← 请求体从空行后开始

第四部分: 请求体 (Request Body)

定义

请求体是可选的,包含要发送到服务器的数据。不是所有请求都有请求体。

何时使用请求体

通常包含请求体的方法:

  • POST - 创建资源或提交表单数据

  • PUT - 更新/替换资源

  • PATCH - 部分更新资源

通常不包含请求体的方法:

  • GET - 虽然技术上可以,但不推荐

  • HEAD - 与 GET 相同,不应有请求体

  • DELETE - 可选,但通常不使用

  • OPTIONS - 通常不使用

  • TRACE - 不应有请求体

请求体的类型

1. application/x-www-form-urlencoded

用途: HTML 表单的默认编码类型

格式: key1=value1&key2=value2

示例:

复制代码
POST /form HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 49

name=John+Doe&email=john%40example.com&age=30

特点:

  • 键值对用 & 分隔

  • 空格编码为 +%20

  • 特殊字符需要 URL 编码

  • 简单高效,适合简单表单

2. multipart/form-data

用途: 上传文件或提交包含二进制数据的表单

格式: 使用边界分隔符分割多个部分

示例:

复制代码
POST /upload HTTP/1.1
Host: example.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Length: 345

------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="username"

John Doe
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="avatar"; filename="photo.jpg"
Content-Type: image/jpeg

[二进制图片数据]
------WebKitFormBoundary7MA4YWxkTrZu0gW--

特点:

  • 每个部分有自己的头字段

  • 可以混合文本和二进制数据

  • 边界字符串不能出现在数据中

  • 适合文件上传

3. application/json

用途: 现代 Web API 的标准数据格式

格式: JSON 对象

示例:

复制代码
POST /api/users HTTP/1.1
Host: api.example.com
Content-Type: application/json; charset=utf-8
Content-Length: 95

{
  "firstName": "John",
  "lastName": "Doe",
  "email": "john.doe@example.com",
  "age": 30
}

特点:

  • 结构化数据

  • 易于解析和生成

  • 支持嵌套对象和数组

  • 现代 RESTful API 的首选

4. application/xml 或 text/xml

用途: XML 格式数据传输

示例:

复制代码
POST /api/data HTTP/1.1
Host: api.example.com
Content-Type: application/xml; charset=utf-8
Content-Length: 145

<?xml version="1.0" encoding="UTF-8"?>
<user>
  <firstName>John</firstName>
  <lastName>Doe</lastName>
  <email>john.doe@example.com</email>
</user>

特点:

  • 结构化标记语言

  • 支持验证和命名空间

  • 较 JSON 更冗长

  • 传统企业应用常用

5. text/plain

用途: 纯文本数据

示例:

复制代码
POST /log HTTP/1.1
Host: example.com
Content-Type: text/plain; charset=utf-8
Content-Length: 45

This is a simple text message without format.
6. application/octet-stream

用途: 任意二进制数据

示例:

复制代码
POST /upload HTTP/1.1
Host: example.com
Content-Type: application/octet-stream
Content-Length: 10240

[二进制数据]

特点:

  • 用于传输原始二进制数据

  • 服务器通常会将其保存为文件

  • 适合下载/上传文件

7. application/graphql

用途: GraphQL 查询

示例:

复制代码
POST /graphql HTTP/1.1
Host: api.example.com
Content-Type: application/graphql
Content-Length: 78

query {
  user(id: "123") {
    name
    email
    posts {
      title
    }
  }
}

请求体大小限制

  • 服务器通常对请求体大小有限制

  • 超过限制会返回 413 Payload Too Large

  • 常见限制: 1MB - 50MB

  • 可通过 Content-Length 头字段预先告知大小


HTTP/1.1 完整请求示例

示例 1: 简单 GET 请求

复制代码
GET /api/users/123 HTTP/1.1
Host: api.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Accept: application/json
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: keep-alive
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0...
Cache-Control: no-cache

注意: GET 请求没有请求体,空行后直接结束

示例 2: POST 创建用户

复制代码
POST /api/users HTTP/1.1
Host: api.example.com
User-Agent: MyApp/1.0
Content-Type: application/json; charset=utf-8
Content-Length: 123
Accept: application/json
Authorization: Bearer token123
Connection: keep-alive

{
  "username": "johndoe",
  "email": "john@example.com",
  "password": "securepass123",
  "role": "user"
}

示例 3: PUT 更新资源

复制代码
PUT /api/users/123 HTTP/1.1
Host: api.example.com
Content-Type: application/json
Content-Length: 89
Authorization: Bearer token123
If-Match: "686897696a7c876b7e"

{
  "email": "newemail@example.com",
  "role": "admin",
  "active": true
}

示例 4: 文件上传

复制代码
POST /api/upload HTTP/1.1
Host: api.example.com
Content-Type: multipart/form-data; boundary=----FormBoundary123
Content-Length: 4567
Authorization: Bearer token123

------FormBoundary123
Content-Disposition: form-data; name="description"

Profile picture upload
------FormBoundary123
Content-Disposition: form-data; name="file"; filename="avatar.jpg"
Content-Type: image/jpeg

[图片的二进制数据]
------FormBoundary123--

示例 5: 条件请求

复制代码
GET /api/data/report.pdf HTTP/1.1
Host: api.example.com
User-Agent: DownloadManager/2.0
Accept: application/pdf
If-Modified-Since: Mon, 01 Jan 2024 00:00:00 GMT
If-None-Match: "abc123def456"
Range: bytes=0-1023
Connection: keep-alive

HTTP/2 的变化

主要区别

HTTP/2 将文本格式改为二进制帧格式,但语义相同。

伪头字段 (Pseudo-headers)

HTTP/2 用伪头字段替代请求行的信息,以 : 开头:

请求伪头字段:

  • :method - HTTP 方法

  • :scheme - 协议方案 (http 或 https)

  • :authority - 主机名和端口(替代 Host 头)

  • :path - 路径和查询字符串

HTTP/2 请求示例 (概念表示):

复制代码
:method: GET
:scheme: https
:authority: api.example.com
:path: /users/123
user-agent: MyApp/1.0
accept: application/json

其他特性

  • 二进制分帧: 消息被分割成帧

  • 多路复用: 单个连接上的多个并发请求

  • 头部压缩: 使用 HPACK 算法压缩头部

  • 服务器推送: 服务器可主动推送资源


HTTP/3 的变化

基于 QUIC

HTTP/3 使用 QUIC 协议(基于 UDP)替代 TCP:

  • 更快的连接建立

  • 改进的拥塞控制

  • 更好的移动网络支持

  • 解决 TCP 队头阻塞问题

语义保持不变

HTTP/3 的请求报文结构和语义与 HTTP/2 基本相同,主要差异在传输层。


请求报文的处理流程

客户端侧

  1. 构建请求行 - 确定方法、目标 URI 和协议版本

  2. 添加必需头字段 - 如 Host (HTTP/1.1 必需)

  3. 添加可选头字段 - 如认证、缓存控制等

  4. 添加空行 - 标记头部结束

  5. 添加请求体 - 如果需要(POST、PUT 等)

  6. 发送到服务器 - 通过 TCP/IP 连接

服务器侧

  1. 接收请求 - 读取 TCP 流

  2. 解析请求行 - 提取方法、URI、协议版本

  3. 解析头字段 - 逐行读取,直到空行

  4. 读取请求体 - 根据 Content-Length 或 Transfer-Encoding

  5. 处理请求 - 根据方法和 URI 执行操作

  6. 生成响应 - 构建响应报文并发送


常见问题和最佳实践

1. 请求方法的选择

  • GET: 获取资源,不修改状态

  • POST: 创建资源或提交复杂数据

  • PUT: 完整替换资源

  • PATCH: 部分更新资源

  • DELETE: 删除资源

2. 头字段使用建议

  • 必须设置 Host: HTTP/1.1 规范要求

  • 明确 Content-Type: 指定请求体格式

  • 设置 Content-Length: 或使用 chunked 编码

  • 使用合适的 Accept: 告诉服务器期望的响应格式

  • 添加 User-Agent: 便于服务器统计和问题排查

  • 适当使用缓存控制: 提升性能

3. 安全性考虑

  • 使用 HTTPS: 加密传输,防止窃听和篡改

  • 不在 URL 中传递敏感信息: 使用请求体或认证头

  • 验证输入: 防止注入攻击

  • 使用强认证: OAuth 2.0、JWT 等

  • 限制请求大小: 防止拒绝服务攻击

  • 实现速率限制: 防止滥用

4. 性能优化

  • 使用 Keep-Alive: 复用连接

  • 启用压缩: gzip、br 等

  • 合理使用缓存: 减少不必要的请求

  • HTTP/2 多路复用: 并行请求

  • 减少头字段大小: 避免过大的 Cookie

5. 调试技巧

  • 使用浏览器开发者工具: Network 标签

  • 使用 curl 命令 : curl -v https://example.com

  • 使用 Postman/Insomnia: API 测试工具

  • 查看原始请求 : curl -v --trace-ascii -

  • 代理工具: Charles、Fiddler、mitmproxy


相关标准文档

RFC 文档

  • RFC 9110: HTTP Semantics (2022) - HTTP 语义

  • RFC 9112: HTTP/1.1 (2022) - HTTP/1.1 协议

  • RFC 9113: HTTP/2 (2022) - HTTP/2 协议

  • RFC 9114: HTTP/3 (2022) - HTTP/3 协议

  • RFC 9111: HTTP Caching (2022) - HTTP 缓存

  • RFC 6265: HTTP State Management (Cookies) - Cookie 管理

  • RFC 7231: HTTP/1.1 Semantics (已被 RFC 9110 取代)

  • RFC 7540: HTTP/2 (已被 RFC 9113 取代)

相关资源


总结

HTTP 请求报文是客户端与服务器通信的基础,由四个部分组成:

  1. 请求行: 定义操作(方法)、目标(URI)和协议版本

  2. 请求头字段: 提供请求的元数据和上下文信息

  3. 空行: 分隔头部和消息体

  4. 请求体: 携带要发送的数据(可选)

理解 HTTP 请求报文的结构和各部分的作用,对于:

  • Web 开发和 API 设计

  • 网络调试和问题排查

  • 性能优化

  • 安全防护

都至关重要。随着 HTTP/2 和 HTTP/3 的普及,虽然传输格式发生了变化,但核心语义保持一致,掌握 HTTP/1.1 的基础知识依然是理解现代 HTTP 协议的关键。

相关推荐
Channing Lewis1 小时前
如何判断邮箱域名是否可以解析
服务器·网络
m0_619731192 小时前
TCP协议实战
网络·网络协议·tcp/ip
芯盾时代2 小时前
“两重“之 经济安全
网络·安全·信息安全·数据安全
Arva .2 小时前
TCP 的粘包 / 拆包机制
网络·网络协议·tcp/ip
真正的醒悟2 小时前
图解网络24
网络·智能路由器
Hello.Reader2 小时前
Flink SQL Join 从 Regular Join 到 Temporal Join 的实战
网络·sql·flink
HIT_Weston2 小时前
54、【Ubuntu】【Gitlab】拉出内网 Web 服务:http.server 单/多线程分析(六)
网络协议·http·gitlab
learning-striving2 小时前
eNSP静态路由配置完整实验
网络·智能路由器·ensp·静态路由
zuozewei2 小时前
南方区域虚拟电厂网络安全系列政策
网络·安全·web安全