我有Spring Boot,我需要在数据库中记录用户操作,所以我编写了HandlerInterceptor:
@Component
public class LogInterceptor implements HandlerInterceptor {
@Autovired
private LogUserActionService logUserActionService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws IOException {
String userName = SecurityContextHolder.getContext().getAuthentication().getName();
String url = request.getRequestURI();
String queryString = request.getQueryString() != null ? request.getQueryString() : "";
String body = "POST".equalsIgnoreCase(request.getMethod()) ? new BufferedReader(new InputStreamReader(request.getInputStream())).lines().collect(Collectors.joining(System.lineSeparator())) : queryString;
logUserActionService.logUserAction(userName, url, body);
return true;
}
}
但是根据这个答案Get RequestBody and ResponseBody at HandlerInterceptor “RequestBody 只能读取一次”,所以据我了解,我读取输入流,然后 Spring 尝试执行相同的操作,但流已被读取,并且我收到错误:“缺少所需的请求正文...”
所以我尝试了不同的方法来制作缓冲输入流,即:
HttpServletRequest httpServletRequest = new ContentCachingRequestWrapper(request);
new BufferedReader(new InputStreamReader(httpServletRequest.getInputStream())).lines().collect(Collectors.joining(System.lineSeparator()))
或者
InputStream bufferedInputStream = new BufferedInputStream(request.getInputStream());
但没有任何帮助 我也尝试使用
@ControllerAdvice
public class UserActionRequestBodyAdviceAdapter extends RequestBodyAdviceAdapter {
但它只有正文,没有 URL 或请求参数等请求信息 也尝试使用过滤器,但结果相同。
所以我需要一种好方法来从请求中获取信息,例如用户、URL、参数、正文(如果存在)并将其写入数据库。
最佳答案
您可以使用Filter
来记录请求正文。
public class LoggingFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request);
try {
chain.doFilter(wrappedRequest, res);
} finally {
logRequestBody(wrappedRequest);
}
}
private static void logRequestBody(ContentCachingRequestWrapper request) {
byte[] buf = request.getContentAsByteArray();
if (buf.length > 0) {
try {
String requestBody = new String(buf, 0, buf.length, request.getCharacterEncoding());
System.out.println(requestBody);
} catch (Exception e) {
System.out.println("error in reading request body");
}
}
}
}
这里要注意的主要一点是,您必须在过滤器链中传递 ContentCachingRequestWrapper
对象,否则您将无法在其中获取请求内容。
在上面的示例中,如果您使用 chain.doFilter(req, res)
或 chain.doFilter(request, res)
那么您将不会获得请求正文wrappedRequest
对象。
关于java - 如何在HandlerInterceptor中读取请求体?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60556148/