
本文详解 Spring Boot 控制器返回非标准 JSON(如调用 toString() 导致的字符串污染)导致前端解析失败的问题,提供基于 Jackson 的正确序列化实践、完整代码示例及关键注意事项。
本文详解 spring boot 控制器返回非标准 json(如调用 `tostring()` 导致的字符串污染)导致前端解析失败的问题,提供基于 jackson 的正确序列化实践、完整代码示例及关键注意事项。
在前后端分离架构中,Angular 通过 HttpClient.get
问题核心在于:List
✅ 正确做法是使用 Jackson 的 ObjectMapper 进行标准 JSON 序列化:
package hibera.web.api.controllers;
import com.fasterxml.jackson.databind.ObjectMapper; // 注意导入路径
import com.google.api.core.ApiFuture;
import com.google.cloud.firestore.CollectionReference;
import com.google.cloud.firestore.DocumentSnapshot;
import com.google.cloud.firestore.QuerySnapshot;
import hibera.web.api.domain.Services;
import hibera.web.api.service.FirebaseInit;
import hibera.web.api.service.ProvidingsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
@RestController
@RequestMapping("/providers")
@CrossOrigin(origins = "http://localhost:4200")
public class ProvidersController {
@Autowired
private FirebaseInit db;
@Autowired
private ProvidingsService service;
@Autowired
private ObjectMapper objectMapper; // ✅ 自动注入 Jackson ObjectMapper
@GetMapping(value = "/getServices", produces = MediaType.APPLICATION_JSON_VALUE)
public String getServices() throws InterruptedException, ExecutionException {
List<Services> servicesList = new ArrayList<>();
CollectionReference serviceRef = db.getFirebase().collection("services_section");
ApiFuture<QuerySnapshot> querySnapshot = serviceRef.get();
for (DocumentSnapshot doc : querySnapshot.get().getDocuments()) {
Services serv = doc.toObject(Services.class);
servicesList.add(serv);
}
// ✅ 正确:将 List 序列化为标准 JSON 字符串
return objectMapper.writeValueAsString(servicesList);
}
}? 关键改进说明:
- @Autowired ObjectMapper:Spring Boot 默认已配置 ObjectMapper(由 spring-boot-starter-web 引入),无需额外依赖;
- produces = MediaType.APPLICATION_JSON_VALUE:显式声明响应 Content-Type 为 application/json,确保 Angular 正确识别;
- 避免 toString():objectMapper.writeValueAsString(...) 生成符合规范的 JSON(无类名、无额外空格/引号污染);
-
类型安全提示:若希望进一步简化,可直接返回 List
(Spring 会自动序列化),但需确保 Services 类有无参构造器和标准 getter 方法:
@GetMapping("/getServices")
public List<Services> getServices() throws InterruptedException, ExecutionException {
// ... 同上数据获取逻辑
return servicesList; // ✅ Spring 自动调用 ObjectMapper 序列化
}⚠️ 注意事项与排查建议:
- 确保 Services 类所有需序列化的字段均为 public 或配有 getter 方法,且无循环引用(否则 ObjectMapper 报 StackOverflowError);
- 若使用 Lombok,请添加 @Data 或明确 @Getter,并确认 @NoArgsConstructor 存在;
- 在 Postman 中验证响应头:Content-Type: application/json 且响应体为纯 JSON 数组(无 " 包裹整个数组);
- Angular 端无需修改 responseType —— 移除 responseType: 'text',保持默认 json 解析模式;
- 如遇中文乱码,在 application.properties 中添加:spring.http.encoding.charset=UTF-8(Spring Boot 2.3+ 改为 server.servlet.encoding.charset=UTF-8)。
遵循以上方案,你的 Angular 应用即可无缝消费 Spring Boot 提供的标准 JSON 接口,彻底解决 Unexpected token 'S' 解析异常。










