Я использую Spring Cloud Gateway с Spring 5, Spring Reactor и Netty для проекта. Для каждого запроса, отправляемого на шлюз, я хочу что-то сделать непосредственно перед отправкой ответа клиенту. Я нашел лучший способ сделать это - добавить действие к ответу с помощью метода beforeCommit.
Я впервые попробовал такой подход:
exchange.getResponse().beforeCommit(() -> {
ServerHttpResponse response = exchange.getResponse();
try {
myActionDoneHere();
response.setStatusCode(OK);
return Mono.empty();
} catch (Exception ex) {
return Mono.error(new MyException(ex));
}
});
И попытался обработать исключение в обработчике исключений:
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
if (isMyException(ex)) {
exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
exchange.getResponse().getHeaders().setContentLength(MSG.length());
exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON_UTF8);
return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(MSG.getBytes())));
}
return Mono.error(ex);
}
Когда я это делаю, у меня возникает исключение, когда я пытаюсь изменить длину содержимого. Если я хорошо понимаю ситуацию. Я больше не могу изменять ответ в моем обработчике, потому что он уже зафиксирован. Поэтому я попробовал другое решение и попытался изменить ответ в моем действии, выполненном непосредственно перед фиксацией:
exchange.getResponse().beforeCommit(() -> {
ServerHttpResponse response = exchange.getResponse();
try {
myActionDoneHere();
response.setStatusCode(OK);
return Mono.empty();
} catch (Exception ex) {
response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
response.getHeaders().setContentLength(MSG.length());
response.getHeaders().setContentType(MediaType.APPLICATION_JSON_UTF8);
return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(MSG.getBytes())));
}
});
На этот раз у меня нет исключений, я могу изменить длину содержимого, но не могу изменить тело ответа.
Так кто-нибудь знает, возможно ли это сделать и как?
Может быть похож на stackoverflow.com/questions/48491098/…, но ответ не помогает, потому что он обрабатывает только исключения
Я использовал технику, которая была внутри WebClientWriteResponseFilter
if (failedAuthorization) {
ServerWebExchangeUtils.setResponseStatus(exchange, HttpStatus.UNAUTHORIZED);
ServerWebExchangeUtils.setAlreadyRouted(exchange);
final Map<String, String> error = Map.of("error", "unauthorized");
return chain.filter(exchange).then(Mono.defer(() -> {
final ServerHttpResponse response = exchange.getResponse();
response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8.toString());
return response.writeWith(new Jackson2JsonEncoder().encode(Mono.just(error),
response.bufferFactory(),
ResolvableType.forInstance(error),
MediaType.APPLICATION_JSON_UTF8,
Hints.from(Hints.LOG_PREFIX_HINT, exchange.getLogPrefix()))
);
}));
}
Я использовал отладчик, чтобы попытаться понять, что происходит, и кажется, что тело написано последним фильтром, которым является NettyWriteResponseFilter. Так что прямо перед фиксацией уже слишком поздно, тело больше недоступно. Но сбивает с толку то, что у меня все еще есть доступ к заголовкам. Итак, если у кого-то есть идея и он знает, как запустить фрагмент кода, который может изменить ответ, прежде чем он будет проверен и отправлен клиенту, я бы действительно хотел знать.