HTTP 请求协议详解
Spring MVC 处理的是 HTTP 请求,理解 HTTP 请求协议的结构,才能搞清楚 @RequestParam、@RequestBody、@RequestHeader 这些注解到底在取哪部分数据。
一、HTTP 请求报文的结构
一个 HTTP 请求由四部分组成:
请求行
请求头
空行
请求体
用文本表示:
POST /api/users HTTP/1.1 ← 请求行
Host: example.com ← 请求头开始
Content-Type: application/json
Content-Length: 45
User-Agent: Mozilla/5.0
← 空行
{"name":"张三","email":"z@example.com"} ← 请求体
空行是请求头和请求体的分隔符。没有请求体时,空行之后直接结束。
二、请求行
请求行包含三部分:
GET /api/users/1?status=active HTTP/1.1
| 请求方法 | GET | HTTP 方法 |
| 请求目标 | /api/users/1?status=active | 路径 + 查询参数 |
| 协议版本 | HTTP/1.1 | HTTP 版本 |
请求目标中的路径和查询参数
/api/users/1?status=active&page=2
- /api/users/1 是路径部分,Spring MVC 用 @PathVariable 获取路径变量。
- ?status=active&page=2 是查询字符串,Spring MVC 用 @RequestParam 获取。
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id,
@RequestParam String status,
@RequestParam(defaultValue = "1") int page) { }
三、请求头
请求头是键值对,描述请求的元信息。常见的请求头:
| Host | 目标主机 | Host: example.com |
| Content-Type | 请求体的媒体类型 | Content-Type: application/json |
| Content-Length | 请求体长度(字节) | Content-Length: 45 |
| Accept | 客户端能接受的响应类型 | Accept: application/json |
| User-Agent | 客户端信息 | User-Agent: Mozilla/5.0 |
| Cookie | 客户端携带的 Cookie | Cookie: sessionId=abc123 |
| Authorization | 认证信息 | Authorization: Bearer xxx |
| Referer | 请求来源页面 | Referer: http://example.com/list |
Spring MVC 获取请求头:
@GetMapping("/info")
public String info(@RequestHeader("User-Agent") String userAgent,
@RequestHeader(value = "X-Token", required = false) String token) {
return userAgent;
}
获取 Cookie:
@GetMapping("/cookie")
public String cookie(@CookieValue("sessionId") String sessionId) {
return sessionId;
}
四、请求体
请求体携带客户端提交的数据。GET 请求通常没有请求体,POST、PUT、PATCH 通常有。
请求体的格式由 Content-Type 决定,常见三种:
1. application/x-www-form-urlencoded
HTML 表单默认提交方式。请求体是键值对,用 & 分隔:
Content-Type: application/x-www-form-urlencoded
name=张三&email=zhangsan@example.com
Spring MVC 获取:
@PostMapping("/form")
public String form(@RequestParam String name,
@RequestParam String email) { }
或者用对象接收:
@PostMapping("/form")
public String form(User user) { }
2. multipart/form-data
文件上传使用的格式。请求体被分成多个部分,每部分有自己的头部:
Content-Type: multipart/form-data; boundary=—-WebKitFormBoundary
——WebKitFormBoundary
Content-Disposition: form-data; name="name"
张三
——WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="a.txt"
Content-Type: text/plain
文件内容
——WebKitFormBoundary–
Spring MVC 获取:
@PostMapping("/upload")
public String upload(@RequestParam String name,
@RequestParam MultipartFile file) { }
3. application/json
前后端分离项目最常用的格式。请求体是 JSON 字符串:
Content-Type: application/json
{"name":"张三","email":"zhangsan@example.com"}
Spring MVC 获取:
@PostMapping("/json")
public User json(@RequestBody User user) { }
@RequestBody 会读取整个请求体,通过 HttpMessageConverter 反序列化成对象。
五、四种参数获取方式对应关系
| URL 路径中的变量 | /users/1 中的 1 | @PathVariable |
| URL 查询参数 | ?status=active | @RequestParam |
| 请求头 | User-Agent: xxx | @RequestHeader |
| Cookie | Cookie: sessionId=abc | @CookieValue |
| 请求体(JSON) | {"name":"张三"} | @RequestBody |
| 请求体(表单) | name=张三&email=… | @RequestParam 或对象接收 |
六、GET 和 POST 在协议层面的区别
| 参数位置 | URL 查询字符串 | 请求体 |
| 是否有请求体 | 通常没有 | 通常有 |
| Content-Length | 通常为 0 | 有值 |
| 幂等 | 是 | 否 |
| 缓存 | 可缓存 | 默认不缓存 |
GET 请求也可以有请求体,但 HTTP 规范不推荐,很多服务器和客户端会忽略。Spring MVC 的 @RequestBody 在 GET 请求中通常拿不到数据。
七、完整请求示例
1. 查询请求
GET /api/users?status=active&page=1 HTTP/1.1
Host: example.com
Accept: application/json
User-Agent: Mozilla/5.0
没有请求体。
2. JSON 提交请求
POST /api/users HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: 52
Accept: application/json
{"name":"张三","email":"zhangsan@example.com"}
3. 表单提交请求
POST /api/login HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
username=admin&password=123456
4. 文件上传请求
POST /api/upload HTTP/1.1
Host: example.com
Content-Type: multipart/form-data; boundary=—-Boundary
——Boundary
Content-Disposition: form-data; name="file"; filename="a.txt"
Content-Type: text/plain
文件内容
——Boundary–
八、Spring MVC 中的完整接收示例
@RestController
@RequestMapping("/api/users")
public class UserController {
// 路径变量 + 查询参数
@GetMapping("/{id}")
public User getById(@PathVariable Long id,
@RequestParam(required = false) String fields) {
return userService.getById(id);
}
// JSON 请求体
@PostMapping
public User create(@RequestBody @Valid User user) {
return userService.save(user);
}
// 表单提交
@PostMapping("/form")
public User createByForm(User user) {
return userService.save(user);
}
// 请求头
@GetMapping("/header")
public String header(@RequestHeader("User-Agent") String ua) {
return ua;
}
// Cookie
@GetMapping("/cookie")
public String cookie(@CookieValue("sessionId") String sessionId) {
return sessionId;
}
// 文件上传
@PostMapping("/upload")
public String upload(@RequestParam MultipartFile file) {
return file.getOriginalFilename();
}
}
九、常见问题
1. 415 Unsupported Media Type
请求的 Content-Type 与接口的 consumes 不匹配。比如接口声明 consumes = "application/json",但客户端发了 text/plain。
2. 400 Bad Request
请求体 JSON 格式错误,或参数类型不匹配。检查 Content-Type 是否为 application/json,JSON 是否合法。
3. @RequestBody 拿不到数据
检查请求方法是否为 POST/PUT/PATCH,Content-Type 是否为 application/json。GET 请求通常没有请求体。
4. @RequestParam 拿不到表单数据
检查 Content-Type 是否为 application/x-www-form-urlencoded。如果是 application/json,表单参数拿不到,需要用 @RequestBody。
5. 中文乱码
检查请求头 Content-Type 是否带了 charset=UTF-8,服务端编码配置是否正确。
十、总结
| 请求行 | 方法、路径、查询参数 | @PathVariable、@RequestParam |
| 请求头 | 元信息、认证、Cookie | @RequestHeader、@CookieValue |
| 空行 | 分隔符 | — |
| 请求体 | 表单、JSON、文件 | @RequestBody、@RequestParam、MultipartFile |
| application/x-www-form-urlencoded | 键值对 | @RequestParam 或对象 |
| multipart/form-data | 分段数据 | MultipartFile |
| application/json | JSON 字符串 | @RequestBody |
HTTP 请求协议的核心是“请求行 + 请求头 + 空行 + 请求体”四部分。路径和查询参数在请求行,元信息在请求头,业务数据在请求体。Spring MVC 的注解就是按这四部分设计的:@PathVariable 取路径,@RequestParam 取查询参数和表单,@RequestHeader 取请求头,@RequestBody 取请求体。把请求结构和注解对应起来,参数绑定就不会搞混。
网硕互联帮助中心

![[玩转Spring]盘点 Spring 常用扩展点:BeanFactoryPostProcessor、BeanPostProcessor、@Enable、自动配置到底该用哪个?-网硕互联帮助中心](https://www.wsisp.com/helps/wp-content/uploads/2026/10/20261011164102-6acbbc1e47136-220x150.png)

评论前必须登录!
注册