JSP中JSON对象属性在JavaScript中转义字符丢失问题
这个问题我之前也碰到过,核心原因是JSP输出到JavaScript时,JSON字符串里的转义字符被模板引擎/浏览器处理掉了,导致JavaScript解析时出现语法错误。让我给你拆解下问题和解决方案:
首先得理清楚为什么会出问题:
你后端用Jackson把对象转成了正确的JSON字符串,比如:[{"commentId":123,"comments": "this \"test\" is here"}]
但当你在JSP里直接把这个字符串插入到JS代码中时(比如var data = ${commentObj};),JSP会直接输出字符串内容,渲染后的JS代码会变成:var data = [{"commentId":123,"comments": "this "test" is here"}];
看到问题了吧?中间的"test"没有被转义,导致JS把"this "当成一个字符串,后面的test就变成了未定义的变量,直接触发语法报错。
接下来给你几个靠谱的解决方案,按推荐程度排序:
方案1:后端直接传递Java对象,JSP中安全转成JSON(最推荐)
不要提前在后端转成JSON字符串,直接把commentObject放到Model里:
// 后端代码 model.addAttribute("commentObject", commentObject);
然后在JSP中,用Jackson的ObjectMapper手动转成JSON,同时确保输出到JS时的转义正确:
<%@ page import="com.fasterxml.jackson.databind.ObjectMapper" %> <% // 从request中获取对象,转成JSON字符串 ObjectMapper mapper = new ObjectMapper(); String commentJson = mapper.writeValueAsString(request.getAttribute("commentObject")); %> <script> // 用单引号包裹JSON字符串,同时转义字符串内的单引号(避免冲突) var comments = JSON.parse('<%= commentJson.replace("'", "\\'") %>'); console.log(comments); // 这里就能正确看到带转义引号的内容了 </script>
这种方法避免了提前转义带来的二次处理问题,而且JSON.parse能确保正确解析JSON结构。
方案2:用JSTL的<c:out>标签处理转义
如果你已经在后端转成了JSON字符串,那可以用<c:out>标签来转义XML/HTML特殊字符,再用JSON.parse解析:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <script> // <c:out>会把双引号转成",JSON.parse会自动转回到双引号 var comments = JSON.parse('<c:out value="${commentObj}" />'); </script>
这个方法的好处是不用写Java脚本,依赖JSTL标签就能搞定,适合不想在JSP里嵌入Java代码的场景。
方案3:后端提前转义JS特殊字符
如果你坚持要在后端转成JSON字符串再传递,可以用工具类把JSON字符串转成适合JS的格式,比如Apache Commons Lang的StringEscapeUtils:
// 后端代码,需要引入Apache Commons Lang依赖 import org.apache.commons.lang3.StringEscapeUtils; ObjectMapper mapper = new ObjectMapper(); String jsonStr = mapper.writeValueAsString(commentObject); // 转义JS中的特殊字符,包括双引号、单引号等 String jsSafeJson = StringEscapeUtils.escapeEcmaScript(jsonStr); model.addAttribute("commentObj", jsSafeJson);
然后在JSP里直接使用:
<script> var comments = ${commentObj}; </script>
escapeEcmaScript会把原JSON里的\"转成\\\",这样JS解析时就能正确识别为转义的双引号了。
最后提醒下,尽量避免在JSP里直接输出未处理的JSON字符串到JS中,不仅容易出现转义问题,还可能存在XSS漏洞,上面的方案都能同时解决这两个问题。
内容的提问来源于stack exchange,提问作者user2623487

