本文目录导读:

- 使用控制台打印(最基础)
- 使用Spring Boot Actuator + HTTP Trace(查看请求原始数据)
- 使用AOP(面向切面编程)统一日志记录
- 使用Spring Boot Filter(过滤器)拦截原始请求
- 使用第三方抓包工具(前端调试)
- 使用Spring的RequestContextHolder获取详情
- 高级方案:使用@RequestBody + 自定义RequestBodyAdvice
- 常见问题及解决
- 总结调试流程
在Java开发中调试接口参数是一个常见需求,主要目的是确认前端传递的参数是否正确、格式是否符合预期,以下是几种常用的调试方法,从简单到深入,适用于不同场景:
使用控制台打印(最基础)
在Controller层或Service层直接打印接收到的参数。
@PostMapping("/api/user")
public String createUser(@RequestBody User user) {
System.out.println("Received user: " + user); // 确保User类重写了toString()
// 或者使用日志框架
log.info("Received user: {}", user);
return "success";
}
适用场景:快速验证,开发调试阶段。 缺点:生产环境需要删除或禁用,否则影响性能和安全。
使用Spring Boot Actuator + HTTP Trace(查看请求原始数据)
开启Actuator的httptrace端点,可以查看最近请求的完整信息(包括Headers、Parameters、Body)。
步骤:
- 添加依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
- 配置
application.yml:management: endpoints: web: exposure: include: httptrace - 启动应用后访问:
http://localhost:8080/actuator/httptrace适用场景:查看完整请求链路,包括时间戳、请求头、参数、响应。
使用AOP(面向切面编程)统一日志记录
通过自定义注解或拦截器,自动打印所有接口的请求参数,避免在每个方法中重复写日志代码。
@Aspect
@Component
public class RequestLogAspect {
@Around("@annotation(org.springframework.web.bind.annotation.RequestMapping) ||
@annotation(org.springframework.web.bind.annotation.PostMapping)")
public Object logParams(ProceedingJoinPoint joinPoint) throws Throwable {
// 获取方法参数
Object[] args = joinPoint.getArgs();
System.out.println("请求参数: " + Arrays.toString(args));
// 执行原方法
Object result = joinPoint.proceed();
System.out.println("响应结果: " + result);
return result;
}
}
适用场景:所有接口统一日志记录,适合中大型项目。 优点:代码无侵入,可控制打印格式(如只打印特定层级)。
使用Spring Boot Filter(过滤器)拦截原始请求
过滤器可以在请求进入Controller之前,读取并打印原始请求参数(包括Body流)。
@Component
public class RequestDebugFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String method = httpRequest.getMethod();
if ("POST".equals(method) || "PUT".equals(method)) {
// 获取Body(注意:Body流只能读取一次,需要包装Request)
String body = getBody(httpRequest);
System.out.println("请求Body: " + body);
}
// 获取Query参数
Map<String, String[]> params = httpRequest.getParameterMap();
System.out.println("Query参数: " + params);
chain.doFilter(request, response);
}
}
注意:Body流只能读取一次,如果后续需要Controller读取,需要使用ContentCachingRequestWrapper包装Request。
使用第三方抓包工具(前端调试)
当需要确认前端是否真的发送了正确的参数(而非后端代码问题)时,使用抓包工具:
- 浏览器开发者工具:Network Tab -> 点击请求 -> Payload / Headers
- Postman / Insomnia:模拟请求,查看发送格式
- Wireshark / Charles:代理抓包,查看原始HTTP报文
使用Spring的RequestContextHolder获取详情
在任意层(Controller、Service)获取当前请求的完整信息。
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
Map<String, String[]> params = request.getParameterMap();
System.out.println("请求参数: " + params);
高级方案:使用@RequestBody + 自定义RequestBodyAdvice
如果你需要统一处理JSON格式的请求体(如解密、校验),可以自定义Advice,在参数转换前打印原始JSON。
@ControllerAdvice
public class CustomRequestBodyAdvice implements RequestBodyAdvice {
@Override
public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
@Override
public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return body;
}
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
// 读取原始JSON
String json = new String(inputMessage.getBody().readAllBytes(), StandardCharsets.UTF_8);
System.out.println("原始JSON: " + json);
return inputMessage; // 注意:这里需要返回可重复读取的流,否则Controller会读到空流
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
System.out.println("转换后的对象: " + body);
return body;
}
}
常见问题及解决
- POST请求的Body流只能读取一次:使用
ContentCachingRequestWrapper包装Request,或者使用Spring的@RequestPart配合CommonsMultipartFile。 - 参数包含特殊字符(如中文、JSON):确保打印时使用
System.out.println或日志框架正确转码。 - 不想生产环境暴露参数:在配置中使用
logging.level控制日志级别,或通过@Profile只在dev环境生效。 - 参数格式混乱(如JSON字符串被转义):使用
ObjectMapper.writerWithDefaultPrettyPrinter()格式化输出。
总结调试流程
- 先确认前端发送了什么:使用浏览器Network或Postman。
- 再确认后端是否收到:使用Filter或AOP在Controller层入口打印。
- 最后分析数据转换后是否异常:使用自定义RequestBodyAdvice或日志框架。
- 长期解决方案:统一使用日志框架(SLF4J + Logback),结合
logbook库自动记录请求/响应(非常推荐)。
推荐工具:
logbook(https://github.com/zalando/logbook):可以自动、格式化记录所有HTTP请求和响应,包括Headers、Params、Body,且可配置忽略某些路径。