仅对某些内容类型应用modifyResponseBody

时间:2019-02-07 05:40:21

标签: spring-cloud spring-cloud-gateway

我正在使用GatewayFilterSpec.modifyResponseBody(标记为“ BETA”功能)来重写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 :(得分:0)

这是一个“解决方案”,其中包含各种问题

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而不使用其结果是很丑陋的。等等。因此,尽管这个“有效”,但并不能使我充满喜悦。