GraphQL响应含多余转义字符的原因及去除方法
问题:GraphQL返回的JSON字符串带多余转义字符,如何解决?
问题现象
我接收的原始无结构化JSON字符串如下:
{ "logo": "http://logo", "name": { "en": "AAA", "ja": "aaa" }, "copyrightText": { "en": "AAA", "ja": "aaa" }, "help": "http://help", "termsAndCondition": "http://terms" }
期望GraphQL接口返回和上面完全一致的内容,但实际返回的响应里带了多余转义字符:
"{ \"logo\": \"http://logo\", \"name\": { \"en\": \"AAA\", \"ja\": \"aaa\" }, \"copyrightText\": { \"en\": \"AAA\", \"ja\": \"aaa\" }, \"help\": \"http://help\", \"termsAndCondition\": \"http://terms\"}"
现有配置与代码
GraphQL Schema
type Query{ getValue: StringApiResponse } type StringApiResponse{ statusCode:String! message:String! timestamp:String! payload:String }
Java 查询实现
@QueryMapping(name = "getValue") public ApiResponse getValue(){ try { String value = ValueService.getValue(); return ApiResponse.forStatus(StatusCode.S0000) .withMessage(StatusCode.S0000.getMessage()) .withPayload(value); } }
转义字符的来源
核心原因是GraphQL Schema里的payload被定义成了String类型:
你传入的是JSON格式的字符串,但GraphQL在序列化String类型字段时,会把字符串内部的双引号做转义处理——因为JSON规范里,字符串必须用双引号包裹,内部的双引号必须转义才能被正确识别为字符串的一部分。最终返回的payload是一个字符串类型的值,而非JSON对象,所以才会出现这些转义字符。
解决方法
方法1:修改Schema,定义结构化Payload类型(推荐)
不要用String来承载JSON结构,直接定义和原始JSON匹配的GraphQL类型,让GraphQL自动序列化正确的JSON对象:
type Query{ getValue: StringApiResponse } type StringApiResponse{ statusCode:String! message:String! timestamp:String! payload: Payload } # 对应原始JSON的结构定义 type Payload { logo: String name: LocalizedText copyrightText: LocalizedText help: String termsAndCondition: String } # 多语言文本结构 type LocalizedText { en: String ja: String }
同时调整Java代码里的ApiResponse,把payload字段的类型从String改成对应的实体类(比如Payload类,包含logo、name等属性,name对应LocalizedText类)。这样返回时GraphQL会直接把对象序列化为JSON对象,不会产生转义。
方法2:使用JSON标量类型(适配无法修改Schema的场景)
如果不能修改Schema,可以通过引入JSON标量类型,让GraphQL把payload当作JSON对象处理:
- 引入支持JSON标量的依赖(比如
graphql-java-extended-scalars) - 修改Schema里的
payload类型为JSON:
type StringApiResponse{ statusCode:String! message:String! timestamp:String! payload: JSON }
- 调整Java代码,把字符串解析为JSON对象再返回:
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @QueryMapping(name = "getValue") public ApiResponse getValue(){ try { String value = ValueService.getValue(); ObjectMapper objectMapper = new ObjectMapper(); JsonNode payloadJson = objectMapper.readTree(value); return ApiResponse.forStatus(StatusCode.S0000) .withMessage(StatusCode.S0000.getMessage()) .withPayload(payloadJson); } catch (Exception e) { // 异常处理逻辑 return ApiResponse.forStatus(StatusCode.ERROR) .withMessage("JSON解析失败"); } }
临时方案说明
你提到的前端用JSON.parse()解析是可行的临时办法,但这相当于把后端的问题转移到了前端处理,从接口设计的角度来说,后端返回正确的JSON结构是更规范的做法。
内容的提问来源于stack exchange,提问作者strz3lmno
相关产品推荐
相关产品推荐

