- JSON 规范中需要转义的特殊字符:这些字符在 JSON 字符串中必须有特殊的转义表示,否则会导致 JSON 格式错误。
- 在特定上下文中需要转义的特殊字符:当 JSON 字符串被嵌入到 HTML、XML 或 JavaScript 代码中时,JSON 字符串内的某些字符(如
<,>,&)也需要被转义。
下面我将详细讲解这两类情况,并提供 Java 中的处理方法。

JSON 规范中的特殊字符(JSON String Escaping)
根据 JSON 规范 (RFC 8259),在 JSON 字符串中,以下字符必须使用反斜杠 \ 进行转义:
| 转义序列 | 代表字符 | 说明 |
|---|---|---|
\" |
双引号 | 用于包裹 JSON 字符串,字符串内部的双引号必须转义。 |
\\ |
反斜杠 \ |
反斜杠本身是转义字符,所以需要转义。 |
\/ |
正斜杠 | 虽然规范中允许不转义,但为了安全,通常也进行转义。 |
\b |
退格 | Backspace |
\f |
换页 | Form feed |
\n |
换行 | Line feed |
\r |
回车 | Carriage return |
\t |
水平制表符 | Tab |
如何处理?
现代的 JSON 处理库(如 Jackson, Gson)在将 Java 对象序列化为 JSON 字符串时,会自动处理这些转义,你不需要手动进行转义。
示例:
假设你有一个包含换行符和双引号的 Java 字符串。

String originalText = "这是一个包含\"双引号\"和\n换行符的文本。";
使用 Jackson 进行序列化:
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonExample {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
String originalText = "这是一个包含\"双引号\"和\n换行符的文本。";
// 直接序列化,Jackson会自动处理转义
String jsonString = mapper.writeValueAsString(originalText);
System.out.println("原始字符串: " + originalText);
System.out.println("JSON字符串: " + jsonString);
// 输出:
// 原始字符串: 这是一个包含"双引号"和
// 换行符的文本。
// JSON字符串: "这是一个包含\"双引号\"和\n换行符的文本。"
}
}
使用 Gson 进行序列化:
import com.google.gson.Gson;
public class GsonExample {
public static void main(String[] args) {
Gson gson = new Gson();
String originalText = "这是一个包含\"双引号\"和\n换行符的文本。";
// 直接序列化,Gson会自动处理转义
String jsonString = gson.toJson(originalText);
System.out.println("原始字符串: " + originalText);
System.out.println("JSON字符串: " + jsonString);
// 输出与Jackson类似
}
}
对于 JSON 规范内的转义,请相信你的 JSON 库,不要手动添加反斜杠,手动添加反而可能导致错误的转义,\"\"\"。
在 Web 上下文中的特殊字符(HTML/JS Escaping)
这是一个更复杂也更常见的问题,当你将 JSON 数据(通常是作为字符串)嵌入到 HTML 页面或 JavaScript 代码中时,就需要进行额外的转义。

场景: 你有一个 JSON 字符串,你想把它放在一个 <script> 标签里,或者作为一个 HTML 属性的值。
问题分析
-
JSON 字符串 vs. JavaScript 字符串:
- JSON 字符串用双引号 包裹。
- JavaScript 字符串可以用单引号 或双引号 包裹。
- 如果你的 JSON 字符串被放入一个用双引号包裹的 JavaScript 字符串中,JSON 字符串内部的双引号
\"就会和外部的双引号冲突,导致语法错误。
错误示例:
<script> var myJson = "这是一个包含"双引号"的文本"; // 语法错误! </script>
-
HTML 实体编码:
- 当 JSON 数据作为 HTML 属性值时(在
data-json属性中),JSON 内容包含<,>,&, , 等字符,可能会破坏 HTML 结构或导致 XSS (跨站脚本) 攻击。
- 当 JSON 数据作为 HTML 属性值时(在
如何处理?
处理这种情况的黄金法则是:逐层转义,从内到外。
数据流的顺序通常是:Java 对象 -> JSON 字符串 -> HTML/JS 上下文
步骤 1:生成 JSON 字符串(由 Jackson/Gson 完成)
如前所述,Jackson/Gson 会生成一个符合 JSON 规范的字符串,其中包含了必要的转义(如 \", \n)。
步骤 2:将 JSON 字符串放入 HTML/JS 上下文(需要手动处理)
你需要根据 JSON 字符串将要放置的位置,选择正确的转义方法。
情况 A:JSON 作为 JavaScript 字符串
最安全的方法是使用 JavaScript 的 JSON.stringify() 函数,这个函数会自动处理所有必要的转义,包括 JSON 规范的转义以及 JavaScript 上下文需要的转义。
推荐做法: 不要在 Java 中拼接 JSON 字符串到 HTML 中,而是让服务器端直接输出一个 JavaScript 对象。
<!-- 错误且危险的做法 -->
<script>
var data = <%-- 直接输出JSON字符串 --%>;
</script>
<!-- 正确且安全的做法 -->
<script>
// 服务器端渲染时,直接输出一个合法的JS对象
var data = {"name": "张三", "bio": "他说:\"你好!\" \n 欢迎来到我的页面。"};
</script>
如果必须从 Java 字符串拼接,那么你需要对字符串进行 JavaScript 转义。
手动转义(不推荐,但为了理解): 你需要对以下字符进行转义:
\->\\- ->
\" - ->
\' - ->
\/ `->\`- 以及控制字符(如换行符
\n)最好替换为\n或其他转义序列。
使用 Apache Commons Lang 的 StringEscapeUtils(推荐手动转义时使用):
import org.apache.commons.text.StringEscapeUtils;
// 假设这是由 Jackson/Gson 生成的标准 JSON 字符串
// "{\"name\": \"O'Reilly\", \"msg\": \"Say \"\"Hello\"\"\"}"
String jsonString = "{\"name\": \"O'Reilly\", \"msg\": \"Say \\\"Hello\\\"\"}";
// 将 JSON 字符串转义为可以在 JS 字符串中使用的形式
String jsEscapedJson = StringEscapeUtils.escapeEcmaScript(jsonString);
// 在 JSP 或 Thymeleaf 中使用
// <script>
// var data = <%= jsEscapedJson %>;
// </script>
// 输出: var data = "{\"name\": \"O'Reilly\", \"msg\": \"Say \\\"Hello\\\"\"}";
注意: StringEscapeUtils.escapeEcmaScript 会处理 和 等字符,使其安全地嵌入 JS 字符串中。
情况 B:JSON 作为 HTML 属性值
当 JSON 作为 HTML 属性(如 <div data-json='...'>)的值时,你需要对 HTML 实体进行转义。
需要转义的字符:
&->&<-><>->>- ->
" - ->
'或'
使用 Apache Commons Lang 的 StringEscapeUtils:
import org.apache.commons.text.StringEscapeUtils;
String jsonString = "{\"name\": \"Smith & Jones\", \"bio\": \"<b>CEO</b>\"}";
// 将 JSON 字符串转义为可以在 HTML 属性中使用的形式
// 使用单引号包裹属性,所以需要转义单引号
String htmlEscapedJson = StringEscapeUtils.escapeHtml4(jsonString);
// 在 JSP 或 Thymeleaf 中使用
// <div data-json='<%= htmlEscapedJson %>'></div>
// 输出: <div data-json='{"name": "Smith & Jones", "bio": "<b>CEO</b>"}'></div>
总结与最佳实践
| 场景 | 处理方法 | 工具/库 |
|---|---|---|
| Java 对象 -> JSON 字符串 | 自动处理,JSON 库会处理所有 JSON 规范要求的转义(, \, \n 等)。 |
Jackson, Gson |
| JSON 字符串 -> JavaScript 字符串 | 最佳实践:在服务端直接输出 JS 对象,而不是 JSON 字符串。 备选方案:如果必须拼接,对 JSON 字符串进行 JavaScript 转义。 |
JSON.stringify() (前端), StringEscapeUtils.escapeEcmaScript() (后端) |
| JSON 字符串 -> HTML 属性值 | 对 JSON 字符串进行 HTML 实体转义。 | StringEscapeUtils.escapeHtml4() (后端) |
核心原则:
- 不要手动处理 JSON 内部的转义:让 Jackson/Gson 这样的库来做,它们已经为你做好了。
- 关注数据输出的最终位置:问题的根源通常不是 JSON 本身,而是 JSON 被嵌入的上下文(HTML 或 JavaScript)。
- 使用成熟的工具库:对于 HTML/JS 转义,优先使用像
org.apache.commons.text.StringEscapeUtils或 OWASP Java Encoder 这样的库,而不是自己实现,以避免遗漏和安全漏洞。 - 防御性编程:始终假设任何来自用户或外部系统的数据都是不安全的,并在输出到任何上下文(Web 页面、API 等)之前进行适当的转义或净化。
