RestController的@ExceptionHandler中的日志请求正文字符串。
默认情况下,当请求是无效的json时,springboot会抛出一个< code > httpmessagenoretreadableexception ,但该消息非常通用,并不包括具体的请求体。这使得调查变得困难。另一方面,我可以使用过滤器记录每个请求字符串,但是这样日志会被太多成功的请求淹没。我只想在请求无效时记录请求。我真正想要的是在< code>@ExceptionHandler中,我将获取该字符串(之前在某个地方获取的)并记录为错误。
为了说明这个问题,我在github中创建了一个演示项目。
@RestController
public class GreetController {
protected static final Logger log = LogManager.getLogger();
@PostMapping("/")
public String greet(@RequestBody final WelcomeMessage msg) {
// if controller successfully returned (valid request),
// then don't want any request body logged
return "Hello " + msg.from;
}
@ExceptionHandler({HttpMessageNotReadableException.class})
public String addStudent(HttpMessageNotReadableException e) {
// this is what I really want!
log.error("{the request body string got somewhere, such as Filters }");
return "greeting from @ExceptionHandler";
}
}
>
有效请求curl-H"Content-Type: application/json"http://localhost:8080--data'{"from":"jim","message":"很高兴认识你!"}'
无效请求(无效JSON)< code > curl-H " Content-Type:application/JSON " http://localhost:8080-data ' { " from ":" Jim "," message " "幸会!"}'
我曾经尝试过HandlerInterceptor
,但会出现如下错误
java.lang.IllegalStateException:在为当前请求调用getReader()后,无法调用getInputStream()。
经过一些搜索1 2,我决定使用过滤器
与内容缓存请求包装器
。
java prettyprint-override"> @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
ContentCachingRequestWrapper cachedRequest = new ContentCachingRequestWrapper(httpServletRequest);
chain.doFilter(cachedRequest, response);
String requestBody = IOUtils.toString(cachedRequest.getContentAsByteArray(), cachedRequest.getCharacterEncoding());
log.info(requestBody);
}
此代码运行良好,只是日志在RestController
之后。如果我更改订单:
String requestBody = IOUtils.toString(cachedRequest.getReader());
log.info(requestBody);
chain.doFilter(cachedRequest, response);
适用于无效请求,但当请求有效时,出现以下异常:
com示例.demo。GreetController:缺少必需的请求正文:public java.lang.String com.example.demo.GreetContrroller.greet(com.exaample.demo.WelcomeMessage)
我还尝试了获取内容数组
,获取输入流
和 getReader
方法,因为一些教程说框架会检查特定的方法调用。
按照@M的建议尝试了CommonsRequestLoggingFilter
。戴恩。
但都是徒劳。
现在我有点困惑。有人能解释一下请求有效和无效时RestController
和Filter
的执行顺序吗?有什么更简单的方法(更少的代码)来实现我的最终目标?谢谢!
我使用的是Spring靴 2.6.3, jdk11.
跟随@M.Deinum的评论,我解决了并希望对别人有用:
public class MyFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
ContentCachingRequestWrapper cachedRequest = new ContentCachingRequestWrapper(httpServletRequest);
chain.doFilter(cachedRequest, response);
}
}
@ExceptionHandler({ HttpMessageNotReadableException.class })
public String addStudent(HttpMessageNotReadableException e, ContentCachingRequestWrapper cachedRequest) {
log.error(e.getMessage());
try {
String requestBody = IOUtils.toString(cachedRequest.getContentAsByteArray(), cachedRequest.getCharacterEncoding());
log.error(requestBody);
} catch (IOException ex) {
ex.printStackTrace();
}
return "greeting from @ExceptionHandler";
}
>
创建一个过滤器,将您的请求包装在ContentCachingRequestWrapper
中(无关紧要)。
使用HttpServletRequest
作为异常处理方法中的参数作为参数
检查ContentCachingRequestWrapper的实例
使用
获取内容字节数组
来获取内容。
像这样。
public class CachingFilter extends OncePerRequestFilter {
protected abstract void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
filterChain.doFilter(new ContentCachingRequestWrapper(request), new ContentCachingResponseWrapper(response));
}
注意:我也包装了响应,以防万一你也想要它。
现在,在您的异常处理方法中使用< code>HttpServletRequest
作为参数,并充分利用这一点。
@ExceptionHandler({HttpMessageNotReadableException.class})
public String addStudent(HttpMessageNotReadableException e, HttpServletRequest req) {
if (req instanceof ContentCachingRequestWrapper) {
ContentCachingRequestWrapper wrapper = (ContentCachingRequestWrapper) req;
log.error(new String(wrapper.getContentAsByteArray()));
}
return "greeting from @ExceptionHandler";
}
可能是多个过滤器将包装器添加到HttpServletRequest
,因此您可能需要迭代这些包装器,您也可以使用
private Optional<ContentCachingRequestWrapper> findWrapper(ServletRequest req) {
ServletRequest reqToUse = req;
while (reqToUse instanceof ServletRequestWrapper) {
if (reqToUse instanceof ContentCachingRequestWrapper) {
return Optional.of((ContentCachingRequestWrapper) reqToUse);
}
reqToUse = ((ServletRequestWrapper) reqToUse).getRequest();
}
return Optional.empty();
}
然后,您的异常处理程序将如下所示
@ExceptionHandler({HttpMessageNotReadableException.class})
public String addStudent(HttpMessageNotReadableException e, HttpServletRequest req) {
Optional<ContentCachingRequestWrapper) wrapper = findWrapper(req);
wrapper.ifPresent(it -> log.error(new String(it.getContentAsByteArray())));
return "greeting from @ExceptionHandler";
}
但这可能取决于您的过滤器顺序以及是否有多个过滤器添加包装器。
Webpack开发服务器代理配置留档: https://webpack.js.org/configuration/dev-server/#devserver-代理 表示它使用http代理中间件: https://github.com/chimurai/http-proxy-middleware#http-代理事件 使用上述链接中记录的功能,我可以执行以下操作: 我的问题是,尽管其他一切都很好——我
我使用的是spring boot Version-2.0.6.Release和spring cloud Version-finchley.sr2
我在Java中使用play框架。我想检索在POST请求中发送到play服务器的整个请求正文。我怎样才能取回它?
问题内容: 我正在将带有JSON正文的POST请求发送到Django服务器(相当标准)。在服务器上,我需要使用进行解码。 问题是如何获取字符串格式的请求正文? 我目前有以下代码: 但是,这给出了一个错误。 如何以正确的编码将请求的主体作为字符串检索? 问题答案: 请求主体,是一个字节字符串。在Python 3中,将仅接受unicode字符串,因此您必须先进行解码,然后再将其传递给。 在Python
使用Grails 4构建一个新的API,我希望可以选择记录完整的请求(标头、方法、内容等)。我可以在Interceptor中看到请求,但是内容只能读取一次(使用),所以在Interceptor中读取它会阻止内容在Controller中可用。 在堆栈溢出中已经有一些类似的问题,通过使用Grails过滤器来解决这个需求。 我不想走这条路的一个原因是,根据Grails文档,过滤器现在被认为是不建议使用的
我试图在flask应用程序上记录post请求,如下所示: 我这样做是因为我怀疑有时我会在POST上得到一个格式错误的JSON对象。我看到的问题是日志包含一个截断的请求体——它似乎被夹在中间... 我不能放日志摘要,因为它是敏感数据。。为什么请求被截断?我做错了吗? 谢谢