Controller 方法參數直接聲明 `HttpServletRequest request`,然後讀取輸入流:
@PostMapping("/api/data")
public ResponseEntity<String> handleRawRequest(HttpServletRequest request) throws IOException {
// 1. 獲取請求體字符串
StringBuilder sb = new StringBuilder();
try (BufferedReader reader = request.getReader()) {
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
}
String requestBody = sb.toString(); // 完整原始請求體 (JSON, XML, 純文本等)
// 2. 業務處理...
String responseBody = process(requestBody);
// 3. 返回
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(responseBody);
}
需攔截響應寫入,使用 `ContentCachingResponseWrapper`:
@Component
public class ResponseLoggingFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request);
ContentCachingResponseWrapper wrappedResponse = new ContentCachingResponseWrapper(response);
try {
filterChain.doFilter(wrappedRequest, wrappedResponse);
} finally {
// 請求體
String reqBody = new String(wrappedRequest.getContentAsByteArray(), StandardCharsets.UTF_8);
// 響應體 (需調用 copyBodyToResponse 才能獲取)
String respBody = new String(wrappedResponse.getContentAsByteArray(), StandardCharsets.UTF_8);
log.info("Request: {} {}", request.getMethod(), request.getRequestURI());
log.info("Request Body: {}", reqBody);
log.info("Response Body: {}", respBody);
wrappedResponse.copyBodyToResponse(); // 關鍵:將緩存的響應寫回真實響應流
}
}
}
Spring Boot 3.0+ 基於 Servlet 6.0,`HttpServletRequest` 內置了 `getInputStream()` 可重複讀取 (需容器支持),但最穩健仍用 `ContentCachingRequestWrapper`。
「我不是要獲得參數,我是要獲得純字符串... 直接在參數裡面寫 request, getInputStream() 就可以了」—— 這是正確的直覺,但要注意流的一次性讀取限制和編碼設置。