1. 案例背景与需求
1.1 需求描述
实现一个留言板功能:
- 页面加载时,获取所有留言并显示。
- 用户填写"谁"、"对谁"、"说什么",点击提交,将留言发送到后端存储。
- 后端存储成功后返回JSON结果,前端将新留言追加到页面,无需刷新。
1.2 为什么用JSON?
因为留言数据包含多个字段,且可能嵌套,JSON能完美表达。同时,前后端分离开发中,JSON是事实标准。
1.3 涉及接口
- 发布留言:
/message/publish(POST) - 获取留言列表:
/message/getList(GET)
1.4 案例演示


2. 接口文档定义
2.1 发布留言接口
| 项目 | 内容 |
|---|---|
| 请求路径 | /message/publish |
| 请求方法 | POST |
| 接口描述 | 发布一条新留言 |
请求参数(JSON格式)
| 参数名 | 类型 | 是否必须 | 说明 |
|---|---|---|---|
| msgFrom | String | 是 | 留言者 |
| msgTo | String | 是 | 接收者 |
| message | String | 是 | 内容 |
请求示例(JSON):
json
{
"msgFrom": "张三",
"msgTo": "李四",
"message": "你好"
}
响应数据
- Content-Type :
application/json;charset=UTF-8 - 响应体 : JSON对象,包含
ok字段,1表示成功,0表示失败
响应示例:
json
{"ok": 1}
2.2 获取留言列表接口
| 项目 | 内容 |
|---|---|
| 请求路径 | /message/getList |
| 请求方法 | GET |
| 接口描述 | 获取所有留言 |
请求参数
无
响应数据
- Content-Type :
application/json;charset=UTF-8 - 响应体: 留言对象数组
响应示例:
json
[
{"msgFrom":"张三","msgTo":"李四","message":"你好"},
{"msgFrom":"王五","msgTo":"赵六","message":"hello"}
]
2.3 为什么这样定义?
- 发布留言需要提交结构化数据,所以用JSON。
- 获取留言返回数组,也适合用JSON。
- 统一使用JSON,前后端解析方便。
3. 前端开发:基于接口文档实现
3.1 留言板页面(messageBoard.html)
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>留言板</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Microsoft YaHei", Arial, sans-serif;
}
body {
background-color: #f5f7fa;
padding: 20px 0;
}
.container {
width: 380px; /* 适度加宽,提升视觉舒适度 */
min-height: 400px; /* 最小高度,避免内容过少时页面塌陷 */
margin: 0 auto;
text-align: center;
background-color: #ffffff; /* 白色背景,突出内容 */
padding: 25px 20px; /* 内边距,让内容不贴边 */
border-radius: 12px; /* 圆角,弱化硬朗感 */
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); /* 轻微阴影,提升层次感 */
}
.container h1 {
color: #333;
font-size: 24px;
margin-bottom: 12px;
font-weight: 600;
}
.grey {
color: #909399; /* 更柔和的灰色 */
font-size: 14px;
margin-bottom: 20px;
display: block; /* 独占一行,提升间距 */
}
.container .row {
width: 100%; /* 改用百分比,适配容器宽度 */
height: 50px; /* 适度加高,提升输入体验 */
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px; /* 行间距,避免拥挤 */
}
.container .row span {
color: #606266;
font-size: 15px;
font-weight: 500;
width: 60px; /* 固定标签宽度,对齐更整齐 */
text-align: left;
}
.container .row input {
width: calc(100% - 70px); /* 自适应宽度,适配容器 */
height: 38px;
padding: 0 12px; /* 内边距,输入文字不贴边 */
border: 1px solid #e5e6eb; /* 浅灰色边框,更柔和 */
border-radius: 6px; /* 圆角输入框 */
font-size: 14px;
outline: none; /* 清除默认外边框 */
transition: border-color 0.2s ease; /* 过渡动画,提升交互感 */
}
/* 输入框聚焦样式,提升交互反馈 */
.container .row input:focus {
border-color: #ff9900; /* 与按钮同色系,视觉统一 */
box-shadow: 0 0 0 2px rgba(255, 153, 0, 0.1); /* 轻微高光,突出聚焦状态 */
}
#submit {
width: 100%; /* 适配容器宽度 */
height: 45px;
background-color: #ff9900; /* 更饱和的橙色,视觉更舒适 */
color: white;
border: none;
margin: 15px 0 20px; /* 调整间距,上下更均衡 */
border-radius: 8px;
font-size: 16px;
font-weight: 500;
cursor: pointer; /* 鼠标悬浮显示手型 */
transition: background-color 0.2s ease; /* 过渡动画 */
}
/* 按钮悬浮效果,提升交互体验 */
#submit:hover {
background-color: #e68a00; /* 稍深的橙色,反馈悬浮状态 */
}
/* 留言列表样式优化 */
.container > div:not(.row) {
padding: 12px 15px;
background-color: #fafafa;
border-radius: 6px;
text-align: left;
color: #333;
font-size: 14px;
margin-bottom: 10px;
border-left: 3px solid #ff9900; /* 左侧小色块,区分留言项 */
word-wrap: break-word; /* 自动换行,避免文字溢出 */
}
</style>
</head>
<body>
<div class="container">
<h1>留言板</h1>
<p class="grey">输入后点击提交, 会将信息显示下方空白处</p>
<div class="row">
<span>谁:</span> <input type="text" name="" id="from">
</div>
<div class="row">
<span>对谁:</span> <input type="text" name="" id="to">
</div>
<div class="row">
<span>说什么:</span> <input type="text" name="" id="say">
</div>
<input type="button" value="提交" id="submit" onclick="submitMessage()">
<!-- <div>A 对 B 说: hello</div> -->
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script>
//我们在页面解析之前,需要将留言板的内容给获取到
$.ajax({
method: "get",
url: "message/getList",
success: function(message) {//返回的是JSON对象
var info = "";
//由于你后端返回的是JSON对象,那么我的前端就可以直接当做对象来使用
if(message !== null && message.length>0){
for(var msg of message) {
info += "<div>" + msg.msgFrom + "对" + msg.msgTo + "说:" + msg.message + "</div>";
}
//最后追加到子标签中
$(".container").append(info);
}
}
})
function submitMessage(){
//当点击提交的时候,我们需要请求后端,然后将东西提交到后台
//此时需要将你提交的数据给提取出来,然后还要进行序列化
//即需要将对象变为JSON字符串
//1. 获取留言的内容
var from = $('#from').val();
var to = $('#to').val();
var say = $('#say').val();
if (from== '' || to == '' || say == '') {
return;
}
$.ajax({
method: "post",
url: "message/publish",
contentType: "application/json",//你前端提交的是JSON,那么你就得指定这个东西,否则后端是不认识的
data: JSON.stringify({//注意,这个东西是一个JSON,他不是对象,网络中无法直接提交对象
msgFrom: from,
msgTo: to,
message: say
}),
success: function(result) {
//如果你的后端返回的是JSON对象,那么前端是可以直接当做对象来使用的
console.log(result.ok);
if(result.ok == 1){//成功【注意如果后端返回的不是JSON对象,那么此时是不可以当做对象来点的】
//2. 构造节点
var divE = "<div>"+from +"对" + to + "说:" + say+"</div>";
//3. 把节点添加到页面上
$(".container").append(divE);
//4. 清空输入框的值
$('#from').val("");
$('#to').val("");
$('#say').val("");
}else{//失败
alert("留言发布失败");
}
}
});
}
</script>
</body>
</html>
3.2 关键点解释
- 获取留言列表:GET请求,无需参数,响应是JSON数组,jQuery自动解析为JavaScript数组,遍历生成HTML。
- 发布留言 :
contentType: "application/json":必须设置,因为后端期待JSON。data: JSON.stringify({...}):将JavaScript对象转为JSON字符串,因为HTTP只能传输字符串。success中的result:由于后端返回JSON对象(响应头application/json),jQuery自动解析为JavaScript对象,所以可以用result.ok。
- 注意 :如果后端返回的是
text/plain,即使内容是{"ok":1},jQuery也不会自动解析,result就是字符串,无法用点语法。
4. 后端开发:根据接口文档实现
4.1 实体类 Message
java
package com.zhongge.demo;
/**
* @ClassName Message
* @Description TODO 留言板信息实体类
* @Author 笨忠
* @Date 2026-02-22 18:20
* @Version 1.0
*/
public class Message {
private String msgFrom;//发送人
private String msgTo;//接受人
private String message;//所说的信息
public String getMsgFrom() {
return msgFrom;
}
public void setMsgFrom(String msgFrom) {
this.msgFrom = msgFrom;
}
public String getMsgTo() {
return msgTo;
}
public void setMsgTo(String msgTo) {
this.msgTo = msgTo;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
4.2 Controller代码
java
package com.zhongge.demo;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName MessageBoardController
* @Description TODO 留言板控制器类
* @Author 笨忠
* @Date 2026-02-22 20:34
* @Version 1.0
*/
@RequestMapping("/message")
@RestController//等价于 @Controller+@Responsebody
public class MessageBoardController {
//这里我们还没有学习到数据库相关的东西,因此我们就先将数据存在内存中
List<Message> list = new ArrayList<>();//使用list集合将我们的留言信息存在内存中
/**
* 发布留言
* @param message 留言对象【谁,对谁,说什么】
* @return 0-失败 1-成功
*/
@PostMapping(value = "/publish", produces = "application/json")
public String publish(@RequestBody Message message) {
//首先就是验证参数
//如果有其中一个是空的,那么我就觉得是不成功,此时就返回:0
if (!StringUtils.hasLength(message.getMsgFrom())
|| !StringUtils.hasLength(message.getMsgTo())
|| !StringUtils.hasLength(message.getMessage())){
return "{\"ok\": 0}";//自己构造一个JSON
}
//将数据存储在集合中
list.add(message);
//然后如果查询走到这里就说明成功,那么此时我就讲数据构造成JSON返回
return "{\"ok\": 1}";
}
/**
* 返回留言信息
* @return 留言信息【集合】
*/
@GetMapping("/getList")
public List<Message> getMessageList() {
return list;
}
}
4.3 关键点解释
@RestController:所有方法返回值直接写入响应体。@PostMapping(value = "/publish", produces = "application/json"):produces = "application/json"告诉Spring这个方法返回的响应内容类型是JSON,这样即使返回String,Spring也会尽量设置响应头为application/json(使用能处理String且支持JSON的转换器,如MappingJackson2HttpMessageConverter)。
@RequestBody Message message:必须加,因为前端发的是JSON,需要从请求体读取并反序列化。- 返回值
String:手动构造JSON字符串。注意:如果去掉produces,响应头将是text/plain,前端就无法自动解析为对象。 getMessageList返回List<Message>:Spring自动用JSON转换器序列化,响应头application/json。
4.4 发布留言的处理流程
-
请求到达,Tomcat解析请求头,
Content-Type: application/json,请求体是JSON字符串。 -
SpringMVC找到
publish方法,@RequestBody触发消息转换器,将JSON反序列化为Message对象。 -
业务处理,存储到list,返回JSON字符串。
-
由于指定了
produces="application/json",Spring使用支持JSON的转换器写入响应,设置响应头application/json。 -
响应报文:

4.5 获取留言列表的处理流程
-
GET请求,无请求体,Tomcat解析后交给Spring。

-
方法返回
list,Spring使用MappingJackson2HttpMessageConverter将list转为JSON数组,响应头application/json。 -
响应报文:

5. 为什么发布接口必须加 produces?
因为返回的是 String,如果不加 produces,Spring默认用 StringHttpMessageConverter,响应头为 text/plain,前端无法自动解析为对象。加上 produces="application/json" 后,Spring会尝试使用能处理 application/json 的转换器(如 MappingJackson2HttpMessageConverter)来写String,从而设置正确的响应头。
更好的做法是返回一个 Map 或自定义对象,让Spring自动转JSON,这样就不需要 produces 了。例如:
java
@PostMapping("/publish")
public Map<String, Integer> publish(@RequestBody Message message) {
Map<String, Integer> result = new HashMap<>();
if (校验通过) {
list.add(message);
result.put("ok", 1);
} else {
result.put("ok", 0);
}
return result;
}
这样返回的是对象,Spring自动用JSON转换器,响应头正确。
6. 深入理解序列化与反序列化
- 序列化 :JavaScript对象 → JSON字符串(前端用
JSON.stringify),Java对象 → JSON字符串(后端用Jackson)。 - 反序列化 :JSON字符串 → JavaScript对象(前端用
JSON.parse或jQuery自动),JSON字符串 → Java对象(后端用@RequestBody+ Jackson)。
HTTP传输的始终是字节流,但通过 Content-Type 约定了解读方式。
7. 接口文档的作用再升华
- 明确了请求和响应的格式,本例中发布接口请求体是JSON,响应也是JSON。
- 规定了是否需要对数据进行序列化/反序列化。
- 避免了前后端因格式不匹配导致的bug。
8. 常见问题
Q1:为什么获取留言列表不需要 produces?
因为返回的是 List,Spring默认用JSON转换器,自动设置响应头为 application/json。
Q2:如果发布接口不加 @RequestBody 会怎样?
后端会尝试从请求参数中取值,但请求体是JSON,不是表单格式,所以参数Map为空,message 对象的所有属性都是null,导致校验失败。
Q3:为什么前端要设置 contentType: "application/json"?
如果不设置,jQuery默认用 application/x-www-form-urlencoded,请求体就会变成 msgFrom=张三&msgTo=李四&message=你好,后端用 @RequestBody 无法解析,因为这不是JSON。
Q4:如果后端返回的JSON字符串不是 {"ok":1} 而是 {"ok":1} 但响应头是 text/plain,前端还能用 result.ok 吗?
不能。因为响应头是 text/plain,jQuery不会自动解析,result 是字符串,没有 ok 属性。除非手动调用 JSON.parse(result)。
9. 详细解释整个流程中 HTTP 是如何通信的
具体的流程如下简图所示:

图中的流程如下:
场景描述
我们有一个留言板页面(messageBoard.html),页面加载时会自动获取已有的留言列表并显示。用户填写"谁"、"对谁"、"说什么"后点击提交,新留言会发送到后端,后端存储后返回成功信息,前端将新留言追加到页面。
第一章:页面加载时的 GET 请求
1.1 浏览器加载页面
我们在浏览器中输入 http://localhost:8080/messageBoard.html,浏览器向服务器请求这个 HTML 文件。服务器返回 HTML,浏览器解析 HTML,遇到 <script> 标签加载 jQuery,然后执行其中的 JavaScript 代码。
1.2 执行 $.ajax GET 请求
javascript
$.ajax({
method: "get",
url: "message/getList",
success: function(message) {
// 处理返回的数据
}
});
method: "get":表示这是一个 GET 请求。url: "message/getList":相对于当前页面的路径,假设当前页面在根路径,则完整 URL 为http://localhost:8080/message/getList。- 没有设置
contentType,因为 GET 请求通常没有请求体,不需要 Content-Type。
1.3 浏览器构造 HTTP 请求
浏览器构造的请求报文如下:

- 请求行:
GET /message/getList HTTP/1.1 - 请求头:
Host表示服务器地址,Accept: */*表示浏览器可以接受任何类型的响应。 - 请求体:空(GET 没有请求体)。
1.4 服务器接收请求
请求到达服务器(Tomcat),Tomcat 解析请求行和请求头,然后根据 URL /message/getList 将请求交给 SpringMVC 的 DispatcherServlet。
1.5 SpringMVC 找到对应方法
DispatcherServlet 根据 @GetMapping("/getList") 找到 MessageBoardController 中的 getMessageList 方法。
java
@GetMapping("/getList")
public List<Message> getMessageList() {
return list;
}
1.6 处理返回值和响应
- 方法返回
List<Message>对象。 - 由于类上有
@RestController,Spring 知道要将返回值直接写入响应体(而不是解析为视图)。 - Spring 遍历
HttpMessageConverter列表,找到能处理List<Message>并支持客户端期望格式的转换器。这里客户端请求头Accept: */*,表示接受任何格式,所以 Spring 会选择默认的 JSON 转换器MappingJackson2HttpMessageConverter(因为项目中有 Jackson 依赖)。 - 转换器将
list对象序列化成 JSON 字符串,例如[{"msgFrom":"张三","msgTo":"李四","message":"你好"}]。 - 同时,Spring 设置响应头
Content-Type: application/json;charset=UTF-8。 - Tomcat 将响应报文发送回浏览器。
1.7 浏览器接收响应
浏览器收到响应报文:

jQuery 的 AJAX 回调中,success: function(message) 被调用。由于响应头是 application/json,jQuery 自动将响应体 JSON 字符串解析为 JavaScript 对象数组,赋值给 message 参数。
1.8 前端处理数据
javascript
if (message !== null && message.length > 0) {
for (var msg of message) {
info += "<div>" + msg.msgFrom + "对" + msg.msgTo + "说:" + msg.message + "</div>";
}
$(".container").append(info);
}
这里 msg 就是一个个 JavaScript 对象,可以直接用 msg.msgFrom 访问属性,因为它是解析后的对象。
关键点 :GET 请求不需要前端设置 Content-Type,但后端返回的响应头 Content-Type: application/json 让前端正确解析为对象。
第二章:提交留言的 POST 请求
2.1 用户输入数据
用户在三个输入框中输入:
- 谁:
张三 - 对谁:
李四 - 说什么:
你好
点击提交按钮,触发 submitMessage() 函数。
2.2 前端获取输入值并构造对象
javascript
var from = $('#from').val(); // "张三"
var to = $('#to').val(); // "李四"
var say = $('#say').val(); // "你好"
// 构造 JavaScript 对象
var dataObj = {
msgFrom: from,
msgTo: to,
message: say
};
此时 dataObj 是内存中的一个对象。
2.3 为什么不能直接发送 dataObj?
因为 HTTP 协议只能传输字节流 ,不能传输内存对象。JavaScript 对象是 JS 引擎特有的数据结构,包含原型、方法等,其他语言(如 Java)无法理解。必须将对象转换成一种通用的、与语言无关的格式,这个过程叫序列化。
2.4 序列化为 JSON 字符串
javascript
JSON.stringify(dataObj)
得到 JSON 字符串:
json
{"msgFrom":"张三","msgTo":"李四","message":"你好"}
这是一个纯文本,可以被编码成字节流发送。
2.5 设置 Content-Type
仅仅有 JSON 字符串还不够,服务器收到字节流后,需要知道如何解读它。所以要在请求头中加上 Content-Type: application/json,告诉服务器:"这是 JSON 格式的数据"。
javascript
contentType: "application/json"
2.6 jQuery 构造 HTTP 请求
jQuery 将构造如下请求报文:

- 请求行:
POST /message/publish HTTP/1.1 - 请求头:
Content-Type指明了请求体格式。 - 请求体:JSON 字符串,被编码为 UTF-8 字节。
2.7 服务器接收请求
Tomcat 接收字节流,解析出请求行、请求头和请求体,封装成 HttpServletRequest 对象,交给 DispatcherServlet。
2.8 SpringMVC 找到方法
DispatcherServlet 根据 URL /message/publish 和 POST 方法找到 publish 方法:
java
@PostMapping(value = "/publish", produces = "application/json")
public String publish(@RequestBody Message message) { ... }
2.9 @RequestBody 的作用
@RequestBody 注解告诉 Spring:这个参数的值要从 HTTP 请求体中获取,并且要根据请求头的 Content-Type 选择合适的消息转换器来反序列化。
2.10 解析请求体的过程
- Spring 从
HttpServletRequest中获取Content-Type头,得到application/json; charset=UTF-8。 - 遍历所有注册的
HttpMessageConverter,找到能处理application/json且能读取Message类型的转换器。这里是MappingJackson2HttpMessageConverter。 - 转换器从请求输入流中读取所有字节,根据字符编码(UTF-8)解码成字符串:
{"msgFrom":"张三","msgTo":"李四","message":"你好"}。 - 使用 Jackson 库将 JSON 字符串反序列化为
Message对象。Jackson 通过反射创建Message实例,然后根据 JSON 中的键名(msgFrom、msgTo、message)调用对应的 setter 方法或直接赋值字段。 - 返回
Message对象,赋值给方法参数message。
此时,Java 内存中有了一个 Message 对象,其属性值与前端输入一致。
2.11 业务处理
方法中先进行参数校验,然后执行:
java
list.add(message); // 将留言添加到内存列表
return "{\"ok\": 1}";
这里返回的是一个 Java 字符串,内容是 {"ok": 1}。
2.12 返回响应时的关键点
方法返回后,Spring 需要将返回值写入响应体。由于类上有 @RestController,返回值会通过 HttpMessageConverter 处理。
问题 :返回值类型是 String,Spring 默认使用 StringHttpMessageConverter。这个转换器默认支持的媒体类型是 text/plain 和 */*,所以它会设置响应头 Content-Type: text/plain;charset=UTF-8,并将字符串原样写入响应体。
但是 ,我们在 @PostMapping 上加了 produces = "application/json"。这个属性告诉 Spring:这个方法生产(返回)的内容类型是 application/json 。Spring 在处理返回值时,会优先考虑能支持 application/json 的转换器。
对于 String 类型,MappingJackson2HttpMessageConverter 也能处理(它会将字符串当作 JSON 值写入),并且它支持 application/json。所以 Spring 会选择 MappingJackson2HttpMessageConverter,设置响应头 Content-Type: application/json;charset=UTF-8,响应体仍是字符串 {"ok": 1}。
如果没有 produces,响应头就是 text/plain。
2.13 响应报文(有 produces)

2.14 前端接收响应
jQuery 收到响应后,检查响应头 Content-Type: application/json,于是自动调用 JSON.parse() 将响应体字符串解析为 JavaScript 对象,赋值给 result 参数。所以 result 是一个对象 { ok: 1 }。
2.15 前端处理响应
javascript
if (result.ok == 1) {
// 构造新留言的 HTML 并追加
var divE = "<div>" + from + "对" + to + "说:" + say + "</div>";
$(".container").append(divE);
// 清空输入框
$('#from').val("");
$('#to').val("");
$('#say').val("");
} else {
alert("留言发布失败");
}
因为 result 是对象,所以 result.ok 能正确取到值 1,条件成立,新留言被添加到页面。
2.16 如果没有 produces,会发生什么?
响应头会是 text/plain,jQuery 不会自动解析 JSON,result 就是一个字符串 "{\"ok\": 1}"。字符串是没有 ok 属性的,所以 result.ok 是 undefined,undefined == 1 为 false,程序会进入 else 分支,弹出"留言发布失败"。这就是为什么加上 produces 后前端才能看懂的原因。
第三章:为什么 getList 不用 produces 也能返回 JSON?【初学者的疑惑点】
因为 getMessageList 返回的是 List<Message>,是一个 Java 对象(非 String)。Spring 在处理对象返回值时,默认会使用 MappingJackson2HttpMessageConverter,自动设置响应头为 application/json。所以不需要额外指定 produces。
而 publish 返回的是 String,Spring 默认用 StringHttpMessageConverter,所以需要 produces 来改变默认行为。
更好的做法是让 publish 也返回一个 Java 对象,比如 Map<String, Integer>,这样 Spring 就会自动转 JSON,无需 produces。
第四章:总结------每一步都清晰
4.1 前端到后端的完整流程
- 用户输入 → 内存中的 JavaScript 对象。
- 序列化 :
JSON.stringify()将对象转为 JSON 字符串。 - 设置 Content-Type :
contentType: "application/json"告诉服务器这是 JSON。 - 发送 HTTP 请求 :请求体为 JSON 字符串,请求头包含
Content-Type。 - 服务器接收:Tomcat 解析请求,SpringMVC 找到方法。
- @RequestBody 触发 :根据
Content-Type选择 JSON 转换器,将请求体反序列化为 Java 对象。 - 业务处理:操作数据,准备返回结果。
- 返回响应 :
- 返回对象(如 List、Map)→ 自动 JSON,响应头
application/json。 - 返回 String → 默认
text/plain,除非用produces指定。
- 返回对象(如 List、Map)→ 自动 JSON,响应头
- 前端接收 :根据响应头
Content-Type解析响应体,得到 JavaScript 对象或字符串。
4.2 核心概念再强调
- 序列化:将内存对象转换为可传输的字节序列(如 JSON 字符串)。
- 反序列化:将字节序列还原为内存对象。
- Content-Type 请求头:告诉服务器请求体的格式。
- Content-Type 响应头:告诉客户端响应体的格式。
- @RequestBody:告诉 Spring 从请求体读取数据,并使用消息转换器反序列化。
- produces:告诉 Spring 方法返回的媒体类型,影响响应头的设置。
第五章:我们可能还有的疑问
5.1 为什么 GET 请求不需要设置 Content-Type?
因为 GET 请求没有请求体,所以不需要描述体格式。Content-Type 只用于描述请求体。
5.2 为什么后端返回 String 时,不加 produces 就是 text/plain?
因为 StringHttpMessageConverter 是专门处理字符串的,它认为字符串就是普通文本,所以默认设置为 text/plain。它不知道你的字符串内容是 JSON 格式。
5.3 如果我把返回的字符串改成 "ok"(不加花括号),前端会怎么样?
如果响应头是 text/plain,前端得到字符串 "ok",result 就是 "ok",无法用 result.ok 访问。如果响应头是 application/json,jQuery 会尝试解析 "ok" 为 JSON,但 "ok" 不是合法的 JSON(合法 JSON 需要是对象、数组或基本类型字符串,但 "ok" 本身作为字符串是合法的 JSON 文本,但 jQuery 解析后得到字符串 "ok",仍然无法用点语法)。所以返回格式要前后端约定一致。
10. 总结
通过三个案例,我们完整地展示了从接口文档定义到前后端实现的全过程,并深入解析了HTTP通信的每个细节。此时我们大概学会了:
- 接口文档是前后端协作的基石。
- HTTP传输的是字节流,需要靠
Content-Type来解读。 - 前端需要根据接口文档选择合适的格式并设置正确的请求头。
- 后端需要根据接口文档使用合适的注解来接收数据,并返回正确的响应头。
- 序列化和反序列化是网络通信的核心。
最后或许我们网络通信大家还有一点迷糊,于是呢我去向AI查了一些相关的资料:彻底搞懂 HTTP 通信:从字节流到对象,前后端数据交换全解析
最后的最后老铁们别忘了点赞👍、关注、加收藏哦👋~