SpringCloud gateway requestのbody検証または変更

6053 ワード

2019.11.05更新:
次のバージョンでは、次のフィルタが追加されました.
org.springframework.cloud.gateway.filter.headers.RemoveHopByHopHeadersFilter
デフォルトでは、次のヘッダが除去されます(この方法の目的は不明です).
- connection
- keep-alive
- te
- transfer-encoding
- trailer
- proxy-authorization
- proxy-authenticate
- x-application-context
- upgrade
これにより、getHeadersメソッドを書き換えるときに追加したtransfer-encodingヘッダが除去され、bodyが解析できなくなります.
解決策:
ymlファイルでカスタムヘッダ除去リストを構成する
spring:
  cloud:
      filter:
        remove-hop-by-hop:
          headers:
            - connection
            - keep-alive
            - te
            - trailer
            - proxy-authorization
            - proxy-authenticate
            - x-application-context
            - upgrade
ソースコードにはリンクが表示され、動的ルーティング構成が実現されます.https://github.com/SingleTigger/SpringCloudGateway-Nacos-Demo
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
往々にしてビジネスでは、ゲートウェイでリクエストパラメータを変更する必要があります(body付きリクエストのみに注意してください).springcloud gatewayには
ModifyRequestBodyGatewayFilterFactory
のfilterは、その実装を見て、入力タイプと出力タイプを指定する必要があります.比較的限られています.
それを参考にブロックを実現しました
注意:アップロードファイルにも要求bodyがあり、特殊な処理が必要です.
 
主なコードは次のとおりです.


import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.cloud.gateway.support.BodyInserterContext;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerStrategies;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiFunction;

/**
 * @author chenws
 * @date 2019/12/12 09:33:53
 */
@Component
public class CModifyRequestBodyGatewayFilterFactory extends AbstractGatewayFilterFactory {

    private final List> messageReaders;

    public CModifyRequestBodyGatewayFilterFactory() {
        this.messageReaders = HandlerStrategies.withDefaults().messageReaders();
    }

    @Override
    @SuppressWarnings("unchecked")
    public GatewayFilter apply(Object config) {
        return (exchange, chain) -> {
            ServerRequest serverRequest = ServerRequest.create(exchange,
                    this.messageReaders);

            Mono modifiedBody = serverRequest.bodyToMono(String.class)
                    .flatMap(originalBody -> modifyBody()
                            .apply(exchange,Mono.just(originalBody)));

            BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody,
                    String.class);
            HttpHeaders headers = new HttpHeaders();
            headers.putAll(exchange.getRequest().getHeaders());
            headers.remove(HttpHeaders.CONTENT_LENGTH);

            CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange,
                    headers);
            return bodyInserter.insert(outputMessage, new BodyInserterContext())
                    .then(Mono.defer(() -> {
                        ServerHttpRequest decorator = decorate(exchange, headers,
                                outputMessage);
                        return chain.filter(exchange.mutate().request(decorator).build());
                    }));

        };
    }

    /**
     *   body
     * @return apply   Mono,       body
     */
    private BiFunction,Mono> modifyBody(){
        return (exchange,json)-> {
            AtomicReference result = new AtomicReference<>();
            json.subscribe(
                    value -> {
                        //value     body,     
                        result.set(value);
                        System.out.println(result.get());
                    },
                    Throwable::printStackTrace
            );
            return Mono.just(result.get());
        };
    }

    private ServerHttpRequestDecorator decorate(ServerWebExchange exchange, HttpHeaders headers,
                                        CachedBodyOutputMessage outputMessage) {
        return new ServerHttpRequestDecorator(exchange.getRequest()) {
            @Override
            public HttpHeaders getHeaders() {
                long contentLength = headers.getContentLength();
                HttpHeaders httpHeaders = new HttpHeaders();
                httpHeaders.putAll(super.getHeaders());
                if (contentLength > 0) {
                    httpHeaders.setContentLength(contentLength);
                }
                else {
                    httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
                }
                return httpHeaders;
            }

            @Override
            public Flux getBody() {
                return outputMessage.getBody();
            }
        };
    }
}
 
 
転載する場合は出典を明記してください.https://blog.csdn.net/shuoshuo132