SpringBoot 接口返回异常全集|JSON解析失败/响应乱码/状态码错误完美解决

SpringBoot 接口开发中,「接口能调用,但返回结果异常」是最常见的问题之一------前端请求正常发起,后端无报错,但前端拿到的是乱码、JSON解析失败、状态码错误(406/415)、返回格式混乱,排查起来一头雾水,尤其前后端分离项目,接口返回异常直接导致页面渲染失败、功能卡壳。

✅ JSON解析失败:Could not read JSON document: Unexpected character; ✅ 接口响应乱码:返回中文变成???、饼饿; ✅ 状态码错误:406 Not Acceptable、415 Unsupported Media Type; ✅ 返回格式异常:本该返回JSON,却返回String/HTML; ✅ 日期格式化异常:返回时间戳/乱码日期,前后端格式不统一; ✅ 空值返回异常:null字段被过滤/返回null导致前端报错。

本篇把 SpringBoot 接口返回的 8大高频异常 一次性讲透,每个异常都配「报错原文+核心根因+可直接复制的解决方案+避坑技巧」,覆盖JSON解析、响应乱码、状态码、日期格式化等全场景,新手照着改就能解决,老手也能查漏补缺,建议收藏,接口开发时直接对照!

一、前置基础:接口返回正常的核心条件

SpringBoot 接口默认返回JSON格式(依赖spring-boot-starter-web),要保证返回正常,需满足3个核心条件:

  1. 引入 spring-boot-starter-web 依赖(自动集成Jackson JSON解析器);

  2. 接口方法添加 @ResponseBody 注解(或类上添加 @RestController,等同于@Controller+@ResponseBody);

  3. 返回对象(POJO/Map/List)可被Jackson正常序列化,无特殊字符、无循环依赖。

关键提醒:接口返回异常,前端报错往往比后端更明显(如控制台提示JSON解析失败),可结合前后端报错一起排查,效率更高!

二、8大高频接口返回异常+解决方案(按出现概率排序)

场景1:接口响应乱码(中文变成???、饼饿)

1. 典型现象/报错

接口返回中文乱码,前端显示为???、饼饿等乱码字符;后端控制台打印正常,仅响应给前端时乱码。

复制代码
// 后端返回预期
{"msg":"操作成功","code":200,"data":"测试中文"}
// 前端实际接收
{"msg":"????","code":200,"data":"饼饿中午"}

2. 核心原因

  • SpringBoot 默认响应编码为 ISO-8859-1(不支持中文),未配置为 UTF-8;

  • 接口返回String类型时,未指定响应编码;

  • 配置文件中字符集配置错误,未全局指定UTF-8。

3. 解决方案(3种任选,优先方案1,全局生效)

复制代码
# 方案1:yml全局配置(推荐,一次配置,全部接口生效)
spring:
  http:
    encoding:
      charset: UTF-8
      force: true  # 强制覆盖默认编码
      enabled: true  # 开启编码配置

# 方案2:接口单独配置(针对单个接口)
@RestController
@RequestMapping("/user")
public class UserController {
    // 单独指定响应编码和返回格式
    @GetMapping(value = "/get", produces = "application/json;charset=UTF-8")
    public Result getUser() {
        return Result.success("测试中文");
    }
}

# 方案3:配置消息转换器(解决复杂乱码场景)
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 配置Jackson JSON转换器,指定UTF-8编码
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        converter.setDefaultCharset(StandardCharsets.UTF_8);
        // 注册转换器
        converters.add(0, converter);
    }
}

场景2:JSON解析失败(Could not read JSON document)

1. 典型报错原文

复制代码
Resolved [org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON document: Unexpected character ('}' (code 125)): was expecting double-quote to start field name
 at [Source: (PushbackInputStream); line: 3, column: 5] (through reference chain: com.xxx.dto.UserDTO["name"]); nested exception is com.fasterxml.jackson.core.JsonParseException: Unexpected character ('}' (code 125)): was expecting double-quote to start field name

2. 核心原因

  • 前端传递的JSON格式错误(如字段未加双引号、逗号遗漏、括号不匹配);

  • 前后端数据类型不匹配(如后端接收Integer,前端传String;后端接收Date,前端传非标准时间格式);

  • 后端实体类缺少无参构造、getter/setter方法,Jackson无法解析;

  • JSON中包含Jackson无法序列化的类型(如LocalDateTime未配置格式化)。

3. 解决方案

  1. 校验前端JSON格式:确保字段用双引号、逗号不遗漏、括号匹配(可通过JSON在线校验工具验证);

  2. 后端实体类规范(必做):

    复制代码
    // 正确实体类:有无参构造、getter/setter、toString
    @Data // Lombok注解,自动生成getter/setter/无参构造
    public class UserDTO {
        private Long id;
        private String name;
        private Integer age;
        // 若有LocalDateTime字段,需配置格式化
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
        private LocalDateTime createTime;
    }
    // 注意:Lombok的@Data注解会自动生成无参构造,若手动写了有参构造,需手动添加无参构造
    @NoArgsConstructor // 手动添加无参构造
    @AllArgsConstructor // 有参构造
    @Data
    public class UserDTO {
        // 字段...
    }
  3. 配置LocalDateTime全局格式化(解决日期解析失败):

    复制代码
    @Configuration
    public class JacksonConfig {
        @Bean
        public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
            return builder -> {
                // 全局配置LocalDateTime格式
                builder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(
                        DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
                ));
                builder.deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer(
                        DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
                ));
            };
        }
    }

    场景3:状态码406 Not Acceptable(无法接受的响应格式)

    1. 典型报错原文

    复制代码
    Resolved [org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation]

    2. 核心原因

    前端请求头中指定了「Accept」格式(如Accept: text/html),但后端接口返回的是JSON格式,两者不匹配;或后端接口无法返回前端要求的格式。

    常见场景:前端请求头Accept设为text/plain,后端返回JSON;或后端接口返回String,前端要求JSON格式。

    3. 解决方案

    1. 统一前后端响应格式:前端请求头Accept设为 application/json(推荐,前后端分离默认);

    2. 后端接口指定返回格式(强制返回JSON):

      复制代码
      // 方法上添加produces,指定返回JSON格式
      @GetMapping(value = "/getUser", produces = "application/json;charset=UTF-8")
      public Result getUser() {
          return Result.success(userService.getUserById(1L));
      }
    3. 排查后端接口返回值:确保返回的是POJO/Map/List(可被Jackson序列化为JSON),避免直接返回String(若返回String,需指定produces为text/plain)。

场景4:状态码415 Unsupported Media Type(不支持的媒体类型)

1. 典型报错原文

复制代码
Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported]

2. 核心原因

前端传递的请求体格式(Content-Type)与后端接口要求的格式不匹配,常见场景:

3. 解决方案

四、生产避坑指南(接口开发必记)

五、总结

SpringBoot 接口返回异常,90% 都是 编码配置错误、JSON格式不规范、序列化配置缺失、前后端约定不一致 这四类问题。核心解决思路是:确保前后端请求/响应格式一致,Jackson能正常序列化返回对象,编码统一为UTF-8

遇到接口返回异常,无需慌乱,按「查前端请求→查后端注解→查序列化配置→查后端日志」的顺序排查,对照本文对应场景修改,就能快速解决。

本文涵盖了接口开发中所有高频返回异常,从基础配置到生产优化,从临时解决到根本规避,新手照着做就能落地,老手也能查漏补缺。

如果这篇文章帮到你了,记得点赞+收藏🌟!评论区说说你遇到过的接口返回异常,一起交流避坑经验~

  • 后端接口用 @RequestBody 接收JSON参数,但前端Content-Type设为 application/x-www-form-urlencoded;

  • 前端传递JSON格式,但Content-Type未设为 application/json;

  • 后端接口不支持前端传递的Content-Type(如前端传multipart/form-data,后端未配置文件上传)。

    3. 解决方案

  • 统一前后端请求格式:

    1. 后端用 @RequestBody 接收参数 → 前端Content-Type设为 application/json,传递JSON格式;

    2. 后端用 @RequestParam 接收参数 → 前端Content-Type设为 application/x-www-form-urlencoded;

  • 前端请求示例(正确传递JSON):

    复制代码
    // 前端axios请求示例
    axios({
        url: "/user/add",
        method: "post",
        headers: {
            "Content-Type": "application/json" // 必须指定
        },
        data: {
            name: "张三",
            age: 20
        }
    })

    后端接口示例(正确接收JSON):

    复制代码
    @PostMapping("/add")
    public Result addUser(@RequestBody UserDTO userDTO) { // @RequestBody接收JSON
        userService.addUser(userDTO);
        return Result.success();
    }

    场景5:日期返回异常(时间戳/乱码/格式不统一)

    1. 典型现象

    接口返回的日期字段为时间戳(如1699999999999)、乱码(如2024-05-20T10:30:00),或前后端日期格式不统一(后端返回yyyy-MM-dd,前端需要yyyy/MM/dd)。

    2. 核心原因

    Jackson默认对LocalDateTime、Date类型的序列化规则,与前端预期不一致;未配置全局日期格式化,导致日期返回格式混乱。

    3. 解决方案(两种任选,优先全局配置)

    复制代码
    # 方案1:全局日期格式化(推荐,所有日期字段生效)
    @Configuration
    public class JacksonConfig {
        @Bean
        public ObjectMapper objectMapper() {
            ObjectMapper objectMapper = new ObjectMapper();
            // 配置Date类型格式化
            objectMapper.registerModule(new JavaTimeModule());
            objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
            // 配置LocalDateTime类型格式化
            objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
            objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            return objectMapper;
        }
    }
    
    # 方案2:单个字段格式化(针对特定字段)
    @Data
    public class UserDTO {
        private Long id;
        private String name;
        // 单个字段指定格式
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
        private LocalDateTime createTime;
        
        @JsonFormat(pattern = "yyyy-MM-dd")
        private Date birthday;
    }

    场景6:接口返回null字段被过滤(前端拿不到null值)

    1. 典型现象

    后端返回的对象中部分字段为null,但前端接收的JSON中没有该字段,导致前端取值报错(如Cannot read property 'xxx' of undefined)。

    2. 核心原因

    Jackson默认配置会过滤掉值为null的字段,或项目中配置了「过滤null字段」的规则,导致null字段不返回。

    3. 解决方案(两种任选)

    复制代码
    # 方案1:全局配置,保留null字段
    @Configuration
    public class JacksonConfig {
        @Bean
        public ObjectMapper objectMapper() {
            ObjectMapper objectMapper = new ObjectMapper();
            // 保留null字段(默认是过滤null)
            objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
            return objectMapper;
        }
    }
    
    # 方案2:单个类/字段配置,保留null字段
    // 单个类:所有字段保留null
    @JsonInclude(JsonInclude.Include.ALWAYS)
    @Data
    public class UserDTO {
        private Long id;
        private String name;
        private String address; // 若为null,会返回该字段
    }
    
    // 单个字段:仅该字段保留null
    @Data
    public class UserDTO {
        private Long id;
        private String name;
        @JsonInclude(JsonInclude.Include.ALWAYS)
        private String address;
    }

    场景7:接口本该返回JSON,却返回String/HTML

    1. 典型现象

    后端接口返回的是POJO对象,但前端接收的是String字符串(如"com.xxx.dto.UserDTO@123456"),或HTML页面(如404页面)。

    2. 核心原因

  • 接口未加 @ResponseBody 注解,或类未加 @RestController 注解(SpringMVC默认返回视图,而非JSON);

  • 接口返回值为Object类型,且未被Jackson序列化(如直接返回Object对象,未指定具体类型);

  • 确保接口正确添加注解:

    复制代码
      // 方式1:类上添加@RestController(推荐)
      @RestController // 等同于@Controller + @ResponseBody
      @RequestMapping("/user")
      public class UserController {
          @GetMapping("/get")
          public Result getUser() {
              return Result.success(userService.getUserById(1L));
          }
      }
    
      // 方式2:方法上添加@ResponseBody
      @Controller
      @RequestMapping("/user")
      public class UserController {
          @GetMapping("/get")
          @ResponseBody // 必须添加,否则返回视图
          public Result getUser() {
              return Result.success(userService.getUserById(1L));
          }
      }
    • 统一接口返回格式:所有接口返回统一的Result对象(避免直接返回POJO/Object);

    • 配置全局异常处理,返回JSON格式错误信息(避免返回HTML):

      复制代码
        @RestControllerAdvice // 全局异常处理
      public class GlobalExceptionHandler {
          // 处理所有异常,返回JSON格式
          @ExceptionHandler(Exception.class)
          public Result handleException(Exception e) {
              return Result.fail(500, e.getMessage());
          }
      }

      场景8:JSON序列化循环依赖(Could not write JSON document)

      1. 典型报错原文

      复制代码
      Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON document: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError)]

      2. 核心原因

      两个实体类互相引用(如User类有OrderList字段,Order类有User字段),Jackson序列化时陷入循环,导致栈溢出。

      3. 解决方案

      使用 @JsonIgnore 注解,忽略循环引用的字段(避免序列化时陷入循环):

      复制代码
      // User类
      @Data
      public class User {
          private Long id;
          private String name;
          // 忽略OrderList字段,避免循环序列化
          @JsonIgnore
          private List<Order> orderList;
      }
      
      // Order类
      @Data
      public class Order {
          private Long id;
          private String orderNo;
          // 忽略User字段,避免循环序列化
          @JsonIgnore
          private User user;
      }

      补充:也可使用 @JsonManagedReference 和 @JsonBackReference 注解,实现双向引用的正常序列化(适合需要保留部分引用字段的场景)。

      三、接口返回异常万能排查步骤(4步定位问题)

    • 查前端请求:检查请求头(Content-Type、Accept)是否正确,JSON格式是否规范;

    • 查后端注解:确认接口类加@RestController、方法加@ResponseBody,返回值为可序列化对象;

    • 查序列化配置:确认Jackson配置正确,日期格式化、null字段处理、循环依赖已解决;

    • 查后端日志:查看控制台是否有序列化异常、参数解析异常,定位具体报错字段。

  • 全局配置优先:统一配置UTF-8编码、日期格式化、Jackson序列化规则,避免单个接口重复配置;

  • 前后端约定一致:提前约定请求格式(Content-Type)、响应格式(JSON)、日期格式,避免不匹配;

  • 实体类规范:所有POJO类必须有无参构造、getter/setter方法,避免Jackson序列化失败;

相关推荐
希望永不加班2 小时前
SpringBoot 编写第一个 REST 接口(Get/Post/Put/Delete)
java·spring boot·后端·spring
vx-程序开发3 小时前
springboot智慧农业信息服务平台-计算机毕业设计源码65287
spring boot·后端·课程设计
小雷君3 小时前
SpringBoot 接口开发5个高频踩坑总结
java·spring boot·后端·面试
陈随易3 小时前
农村程序员聊五险一金
前端·后端·程序员
树獭叔叔3 小时前
OpenClaw 多 Agent 通信机制解析:sessions_spawn 与 sessions_send
后端·aigc·openai
REI-3 小时前
黑马点评项目启动
java·后端
我真会写代码4 小时前
SpringBoot自动装配原理:告别繁琐配置,读懂底层逻辑
java·spring boot·mybatis
尽兴-4 小时前
Spring Boot 整合 Elasticsearch 8.x 实战总结(含三种实现方式 + 完整示例)
spring boot·elasticsearch·jenkins
Cosolar4 小时前
AgentScope-Java ReActAgent 代码实现讲解
人工智能·后端·面试