java - 如果发生异常,则记录http请求正文

标签 java spring-boot request

我一直在使用 Spring Boot 开发 REST API 服务。 这是我的休息 Controller

@RequestMapping(value = "owner/login", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    @ResponseBody
    public ResponseEntity<String> login(@RequestBody Owner owner) throws TimeoutException, SocketTimeoutException, SocketException {
        controller.login(owner);
        return ResponseEntity.ok("\"error\": 0");
    }

这是 Controller

 public JsonObject login(Owner loginOwner){
        Map<String,String> params = new HashMap<String,String>();
        params.put("email", loginOwner.getEmail());
        params.put("password", loginOwner.getPassword());
        if(GMoikaStringUtils.isEmpty(loginOwner.getEmail()) || !GMoikaStringUtils.isValidEmail(loginOwner.getEmail())){
            throw new InvalidUserInputException("Wrong email format", CLASS_NAME, "login", params, "owners/owner/login POST");
        }
        else{
            someLogic...
        }
    }

问题是,使用这个结构我应该在每个方法内创建带有参数的映射。如何避免在每个方法内创建映射并将所有参数放入该映射中?我需要“MAP”在日志中显示参数,以防发生异常。 也许 spring boot 可以做到这一点,但我在官方文档中找不到我的案例。提前致谢

最佳答案

如果您只想在抛出 InvalidUserInputException 后执行此操作,则可以编写一个异常处理程序:

@ExceptionHandler(InvalidUserInputException.class)
@ResponseBody
public ValidationError getError(InvalidUserInputException ex) {
    // ...
}

由于 InvalidUserInputException 是自定义异常,因此您可以添加一个 Object 类型的字段,您可以在其中传递请求正文,例如:

throw new InvalidUserInputException("Wrong email format", loginOwner);

现在您可以使用 Owner 对象的 toString() 方法来记录它。如果你想以JSON方式获取,可以使用 Apache commons和他们的ToStringBuilder :

@Override
public String toString() {
    return new ToStringBuilder(this, ToStringStyle.JSON_STYLE)
        .append("email", email)
        .append("password", password)
        .toString();
}
<小时/>

或者,如果您不想依赖使用 toString() 方法而只想返回纯请求正文,您也可以将 HttpServletRequest 添加为异常处理程序的参数。

在执行此操作之前,您必须将其包装起来,因为请求正文只能读取一次,为了克服该问题,您应该在读取请求正文后“缓存”请求正文。为此,您可以使用 Spring 的 ContentCachingRequestWrapper .

要包装它,您应该编写自己的Filter。您可以通过从 Spring 扩展它们的 OncePerRequestFilter 来做到这一点像这样:

ContentCachingRequestWrapper wrapper = (ContentCachingRequestWrapper) request;
wrapper.getContentAsByteArray();

@Component
public class RequestWrapperFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        filterChain.doFilter(new ContentCachingRequestWrapper(httpServletRequest), httpServletResponse);
    }
}

现在,您可以通过调用 getContentAsByteArray() 方法在异常处理程序中获取请求正文。要获取字符串形式的请求正文,您可以使用 Apache Commons 中的 IOUtils:

ContentCachingRequestWrapper wrapper = (ContentCachingRequestWrapper) request;
logger.warn("Input validation failed, request body: {}", IOUtils.toString(wrapper.getContentAsByteArray(), wrapper.getCharacterEncoding()));

这会将整个请求正文记录为字符串。不过,记录敏感信息时要小心。

关于java - 如果发生异常,则记录http请求正文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45633154/

相关文章:

java - 如何为@CachePut定义多个键?

java - Tomcat 中的 Web 应用程序 : reading from a DB works but nothing gets persisted?

java - 如何编写不创建要在 spring 配置生命周期中运行的 bean 的启动逻辑?

spring-boot - STS4 - application.properties 中没有内容帮助

c# - 如何检查HTTP请求是否是外部的

java - 如何从java中的线程传播异常?

spring - 无需用户登录即可保护 Spring Boot 应用程序

spring - Spring Boot 1.4 未获取 CORS header

html - 新行字符的提交方式不同

node.js cookie 与 request.jar