Как изменить тело ответа в Spring Cloud Gateway непосредственно перед фиксацией

Я использую 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())));
    }
});

На этот раз у меня нет исключений, я могу изменить длину содержимого, но не могу изменить тело ответа.

Так кто-нибудь знает, возможно ли это сделать и как?


person Pit    schedule 30.04.2018    source источник
comment
Я использовал отладчик, чтобы попытаться понять, что происходит, и кажется, что тело написано последним фильтром, которым является NettyWriteResponseFilter. Так что непосредственно перед фиксацией уже слишком поздно, тело больше недоступно. Но что сбивает с толку, так это то, что у меня все еще есть доступ к заголовкам. Поэтому, если у кого-то есть идея и он знает, как запустить фрагмент кода, который может изменить ответ до его проверки и отправки клиенту, я бы очень хотел знать.   -  person Pit    schedule 30.04.2018
comment
Может быть похоже на stackoverflow.com/questions/48491098/, но ответ не помогает, потому что он обрабатывает только исключения   -  person Archimedes Trajano    schedule 09.02.2019


Ответы (1)


Я использовал технику, которая была внутри 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()))
            );
        }));
    }
person Archimedes Trajano    schedule 09.02.2019