Spring Boot GET接口返回重复响应体问题排查求助
排查Spring Boot GET接口返回重复响应体的问题
根据你提供的代码和响应示例,以下是逐步排查和解决思路:
1. 先确认控制器方法是否被执行两次
在getUserById和existByEmail方法中添加日志,直接打印调用记录:
@GetMapping("/{id}") public ResponseEntity<?> getUserById(@PathVariable("id") String userId) { System.out.println("GET /v0/api/user/" + userId + " 执行"); UserResponse user = this.userApplication.findById(userId); EntityModel<UserResponse> entityModel = this.requestResponseAssembler.toEntityModel(user); return ResponseEntity.ok(entityModel); } @RequestMapping(value = "/{email}", method = RequestMethod.HEAD) public ResponseEntity<?> existByEmail(@PathVariable("email") String email) { System.out.println("HEAD /v0/api/user/" + email + " 执行"); if (userApplication.checkIfUserExistByEmail(email)) return ResponseEntity.status(HttpStatus.FOUND).build(); return ResponseEntity.notFound().build(); }
调用接口后查看控制台:
- 如果两个方法的日志都出现,说明路径匹配冲突:
/{id}和/{email}都是通用路径变量,当请求的ID格式类似邮箱时,可能触发HEAD接口的匹配(虽然指定了HEAD方法,但某些客户端可能同时发送GET+HEAD请求)。 - 如果只有
getUserById的日志出现两次,说明方法被重复执行,问题出在AOP、拦截器或请求重复发送上。
2. 排查请求是否被重复发送
用curl或Postman单独调用一次接口,观察请求次数:
curl -v http://localhost:8080/v0/api/user/8db4c6ab-0872-4688-8cc2-26ea93019f78
- 如果响应仍然重复,说明问题在服务端;
- 如果响应正常,说明客户端(浏览器/前端代码)发送了两次请求。
3. 检查过滤器/拦截器是否重复写入响应
查看项目中自定义的Filter或Interceptor,比如继承OncePerRequestFilter的类,检查是否存在以下问题:
- 重复调用
chain.doFilter(request, response); - 在过滤器中额外写入响应内容,导致和控制器的输出叠加。
比如这类错误代码:
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { filterChain.doFilter(request, response); // 额外写入响应,导致重复输出 response.getWriter().write("冗余内容"); }
4. 排查Spring HATEOAS序列化问题
因为你返回的是EntityModel(Spring HATEOAS类型),可能存在序列化重复的情况:
- 暂时修改接口返回普通
UserResponse,看是否还会重复:
@GetMapping("/{id}") public ResponseEntity<?> getUserById(@PathVariable("id") String userId) { UserResponse user = this.userApplication.findById(userId); return ResponseEntity.ok(user); }
如果此时响应正常,说明问题出在HATEOAS的序列化环节:
- 检查Spring Boot和Spring HATEOAS的版本兼容性(Java 17需要Spring Boot 3.x + Spring HATEOAS 2.x);
- 查看是否自定义了
HttpMessageConverter,导致JSON序列化被执行两次。
5. 检查AOP切面是否重复调用方法
如果项目中有AOP环绕通知,确认是否重复调用了proceed():
@Around("execution(* com.example.controller.UserResource.getUserById(..))") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { // 错误:调用了两次proceed(),导致方法执行两次 joinPoint.proceed(); return joinPoint.proceed(); }
常见修复方案
- 路径冲突:修改HEAD接口的路径,比如改为
/exists/{email},避免和GET接口的/{id}重叠; - 过滤器问题:修正过滤器逻辑,确保只处理一次响应;
- AOP问题:保证
proceed()只调用一次; - HATEOAS版本问题:升级或降级依赖,确保版本兼容。
内容的提问来源于stack exchange,提问作者eynoc
相关产品推荐
相关产品推荐

