Применять modifyResponseBody только для определенного типа контента - PullRequest
0 голосов
/ 07 февраля 2019

Я использую GatewayFilterSpec.modifyResponseBody (помеченный как функция «БЕТА») для перезаписи полезных нагрузок JSON.Это работает хорошо, пока полезные данные ответа на самом деле имеют тип контента application/json.В моем случае это, к сожалению, не всегда гарантировано, и я хотел бы, чтобы он применял modifyResponseBody только в том случае, если ответ имеет заголовок Content-Type: application/json, иначе пропустите фильтр.Возможно ли это с помощью Spring Cloud Gateway и как это сделать?Спасибо.

Теперь я получаю это:

org.springframework.web.reactive.function.UnsupportedMediaTypeException: Content type 'text/html' not supported
    at org.springframework.web.reactive.function.BodyInserters.lambda$null$11(BodyInserters.java:329)
    at java.util.Optional.orElseGet(Optional.java:267)
    at org.springframework.web.reactive.function.BodyInserters.lambda$bodyInserterFor$12(BodyInserters.java:325)

1 Ответ

0 голосов
/ 11 февраля 2019

Вот «решение», имеющее всевозможные проблемы :

package my_package;

import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.rewrite.ModifyResponseBodyGatewayFilterFactory;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import static org.springframework.http.MediaType.APPLICATION_JSON;

@Component
@Primary
public class JsonOnlyModifyResponseBodyGatewayFilterFactory extends ModifyResponseBodyGatewayFilterFactory {
    public JsonOnlyModifyResponseBodyGatewayFilterFactory(ServerCodecConfigurer codecConfigurer) {
        super(codecConfigurer);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return new MyModifyResponseGatewayFilter(config);
    }

    public class MyModifyResponseGatewayFilter extends ModifyResponseGatewayFilter {
        MyModifyResponseGatewayFilter(Config config) {
            super(config);
        }

        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            ServerHttpResponse serverHttpResponse = getServerHttpResponseFromSuper(exchange);
            ServerHttpResponseDecorator responseDecorator = new ServerHttpResponseDecorator(exchange.getResponse()) {
                @Override
                public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                    if (APPLICATION_JSON.isCompatibleWith(getDelegate().getHeaders().getContentType())) {
                        return serverHttpResponse.writeWith(body);
                    }
                    return super.writeWith(body);
                }
            };
            return chain.filter(exchange.mutate().response(responseDecorator).build());
        }

        private ServerHttpResponse getServerHttpResponseFromSuper(ServerWebExchange exchange) {
            ServerHttpResponse[] serverHttpResponse = new ServerHttpResponse[1];
            //noinspection UnassignedFluxMonoInstance
            super.filter(exchange, chain -> {
                serverHttpResponse[0] = chain.getResponse(); // capture the response when the super sets it
                return null;
            });
            return serverHttpResponse[0];
        }
    }
}

Выбранный подход вместо простого изменения существующей копии ModifyResponseBodyGatewayFilterFactory,Это позволяет обновлять версии Spring Boot Gateway, внося незначительные изменения ModifyResponseBodyGatewayFilterFactory.Но так как JsonOnlyModifyResponseBodyGatewayFilterFactory очень зависит от реализации ModifyResponseBodyGatewayFilterFactory, это может легко сломаться.Еще одним недостатком этого решения является то, что мне пришлось поместить аннотацию @Primary, чтобы избежать исключения required a single bean, but 2 were found, но оно переопределяет значение по умолчанию, которое предположительно повлияет на другие варианты использования modifyResponseBody.Ужасно звонить super.filter и не использовать его результат.И так далее.Так что, хотя это «работает», оно не дает мне радости.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...