ich die folgenden Dinge in meinem Spring MVC-Anwendung haben:Log Antworttext nach asynchronen Spring MVC Controller-Methode
@RestController
public class SomeController {
@GetMapping(value = "/csv", produces = { "text/csv", MediaType.APPLICATION_JSON_VALUE })
public Future someAsyncMethod() {
return CompletableFuture
.supplyAsync(() -> generateCsvSlowly()))
.thenApply(csv -> {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Content-Disposition", "attachment; filename=" + "Filename_.csv");
httpHeaders.add("Cookie", "fileDownload=true; path=/");
return new HttpEntity<>(csv, httpHeaders);
});
}
}
}
So erzeugt es einfach csv aber so langsam, dass ich diesen Anruf asynchron machen.
Ich versuche, alle Antworttext auf folgende Weise zu protokollieren:
@Component
public class LoggingFilter extends OncePerRequestFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(LoggingFilter.class);
private static final AtomicLong ID = new AtomicLong();
static final String SOME_FORMAT_STRING = ...;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
long id = ID.incrementAndGet();
HttpServletResponse responseToUse = response;
if (!(response instanceof ContentCachingResponseWrapper)) {
responseToUse = new ContentCachingResponseWrapper(response);
}
try {
filterChain.doFilter(request, responseToUse);
}
finally {
byte[] responseBodyBytes = ((ContentCachingResponseWrapper) responseToUse).getContentAsByteArray();
LOGGER.info(SOME_FORMAT_STRING, id, responseToUse.getStatus(), responseToUse.getContentType(),
new ServletServerHttpResponse(responseToUse).getHeaders(), new String(bodyBytes, UTF_8));
((ContentCachingResponseWrapper) responseToUse).copyBodyToResponse();
}
}
}
Hier ist meine Exception-Handler:
@ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(ApplicationException.class)
@ResponseBody
public ResponseEntity<Status> handleException(ApplicationException exception) {
Status status = new Status();
...
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
...
return new ResponseEntity(status, headers, exception.getHttpCodeMvc());
}
@Override
protected ResponseEntity handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
return handleException(new ApplicationException(ex, ApplicationStatus.GENERIC_ERROR));
}
}
Hier Status
ist einfach POJO und ApplicationException
ist eine benutzerdefinierte Ausnahme Klasse.
Wenn generateSlowlyCsv
eine Ausnahme auslöst, wird sie in handleException
verarbeitet, aber nichts wird protokolliert, und es wird keine Nachricht an den Client zurückgegeben. Andere nicht-asynchrone Controller-Methoden protokollieren einen Fehler (auch den gleichen) und senden den Antworttext zurück. Wenn csv generiert wird (ich sah es im Debugger) ohne Fehler, hängt der Aufruf einfach und ich kann nicht finden, wo (es kommt von completable Zukunft zurück). Ohne LoggingFilter
funktioniert alles gut, aber natürlich ohne Logs.
Wie kann ich Response-Body nicht verlieren, wenn eine Ausnahme aufgetreten ist und CSV zurückgeben, wenn es generiert wird? Vielen Dank!
P.S. Wiederkehr Callable
und MvcAsyncTask
aus der Controller-Methode auch nicht