SpringCloud GateWay通过过滤器GatewayFilter修改请求或响应内容

这篇具有很好参考价值的文章主要介绍了SpringCloud GateWay通过过滤器GatewayFilter修改请求或响应内容。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Spring Cloud Gateway在有些场景中需要获取request body内容进行参数校验或参数修改,我们通过在GatewayFilter中获取请求内容来获取和修改请求体,下面我们就基于ServerWebExchange来实现:

ServerWebExchange命名为服务网络交换器,存放着重要的请求-响应属性、请求实例和响应实例等等,有点像Context的角色,其中有两个重要的接口方法:

   // 获取ServerHttpRequest对象
    ServerHttpRequest getRequest();

    // 获取ServerHttpResponse对象
    ServerHttpResponse getResponse();

创建一个GatewayFilter,必须实现Ordered接口,返回一个小于-1的order值,这是因为NettyWriteResponseFilter的order值为-1,我们需要覆盖返回响应体的逻辑,自定义的GlobalFilter必须比NettyWriteResponseFilter优先执行。

public class RequestGatewayFilter implements GatewayFilter, Ordered {
@Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        HttpHeaders headers = request.getHeaders();

        // 处理参数
        MediaType contentType = headers.getContentType();

        if (exchange.getRequest().getMethod().equals(HttpMethod.POST)) {
        //Content-type为“application/json”
            if (MediaType.APPLICATION_JSON.isCompatibleWith(contentType)) {
                return readBody(exchange, chain);
            }
            //Content-type为“application/x-www-form-urlencoded”
            else if(MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(contentType)){
                GatewayContext gatewayContext = new GatewayContext();
                gatewayContext.setRequestHeaders(headers);
                gatewayContext.getAllRequestData().addAll(request.getQueryParams());
                exchange.getAttributes().put(GatewayContext.CACHE_GATEWAY_CONTEXT,gatewayContext);

                return readFormData(exchange, chain, gatewayContext);

            }
//Content-type为“multipart/form-data”
else if (MediaType.MULTIPART_FORM_DATA.isCompatibleWith(contentType)) {
                GatewayContext gatewayContext = new GatewayContext();
                gatewayContext.setRequestHeaders(headers);
                gatewayContext.getAllRequestData().addAll(request.getQueryParams());
                exchange.getAttributes().put(GatewayContext.CACHE_GATEWAY_CONTEXT,gatewayContext);

                return readMultipartData(exchange, chain, gatewayContext);
            }
        } else {
            return readGetData(exchange, chain);
        }
        return chain.filter(exchange);
    }
    @Override
    public int getOrder() {
        return -2;
    }
}

处理content-type为application/json的方法:

/**
     * ReadJsonBody
     *
     * @param exchange
     * @param chain
     * @return
     */
    private Mono<Void> readBody(ServerWebExchange exchange, GatewayFilterChain chain) {
        /**
         * join the body
         */
        return DataBufferUtils.join(exchange.getRequest().getBody()).flatMap(dataBuffer -> {
            byte[] bytes = new byte[dataBuffer.readableByteCount()];
            dataBuffer.read(bytes);
            DataBufferUtils.release(dataBuffer);
           
            /**
             * validate request params or form data
             */
            Result checkResult = null;
            try {
                String bodyString = new String(bytes, "utf-8");
                Map bodyMap = JSONObject.parseObject(bodyString,Map.class);

                //校验参数
                checkResult = validParam(exchange, bodyMap);
                if(checkResult.getCode()!=0){
                    return  errorInfo(exchange, checkResult.getCode(), checkResult.getMessage());
                }
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }

            Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
                DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
                DataBufferUtils.retain(buffer);
                return Mono.just(buffer);
            });
            /**
             * repackage ServerHttpRequest
             */
            ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {
                @Override
                public Flux<DataBuffer> getBody() {
                    return cachedFlux;
                }
            };

            ServerHttpResponse originalResponse = exchange.getResponse();
            originalResponse.getHeaders().setContentType(MediaType.APPLICATION_JSON);
            DataBufferFactory bufferFactory = originalResponse.bufferFactory();
            ServerHttpResponseDecorator response = buildResponse(originalResponse, bufferFactory, (Map)checkResult.getResult());
            /**
             * mutate exchage with new ServerHttpRequest
             */
            ServerWebExchange mutatedExchange = exchange.mutate().request(mutatedRequest).response(response).build();
            /**
             * read body string with default messageReaders
             */
            return ServerRequest.create(mutatedExchange, MESSAGE_READERS).bodyToMono(String.class)
                    .doOnNext(objectValue -> {
                        log.debug("[GatewayContext]Read JsonBody:{}", objectValue);
                    }).then(chain.filter(mutatedExchange));
         
        });
    }

处理content-type为application/x-www-form-urlencoded的方法:

/**
     * ReadFormData
     * @param exchange
     * @param chain
     * @return
     */
    private Mono<Void> readFormData(ServerWebExchange exchange, GatewayFilterChain chain, GatewayContext gatewayContext){
        HttpHeaders headers = exchange.getRequest().getHeaders();
        return exchange.getFormData().switchIfEmpty(
                        Mono.defer(() -> Mono.just(new LinkedMultiValueMap<>()))
                ).flatMap(formDataMap -> {
                    Charset charset = headers.getContentType().getCharset();
                    charset = charset == null? StandardCharsets.UTF_8:charset;
                    String charsetName = charset.name();
                    MultiValueMap<String, String> paramMap = exchange.getRequest().getQueryParams();
                    Map map = convertMap(paramMap);
                    /*
                     * formData is empty just return
                     */
                    if((null == formDataMap || formDataMap.isEmpty()) && (null == map || map.isEmpty())){
                        return chain.filter(exchange);
                    }
                    StringBuilder formDataBodyBuilder = new StringBuilder();
                    String entryKey;
                    List<String> entryValue;
                    try {
                        /*
                         * repackage form data
                         */
                        for (Map.Entry<String, List<String>> entry : formDataMap.entrySet()) {
                            entryKey = entry.getKey();
                            entryValue = entry.getValue();
                            if (entryValue.size() > 1) {
                                for(String value : entryValue){
                        formDataBodyBuilder.append(entryKey).append("=").append(value).append("&");
                                }
                            } else {
                                       formDataBodyBuilder.append(entryKey).append("=").append(entryValue.get(0)).append("&");
                            }
                        }
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    /*
                     * substring with the last char '&'
                     */
                    String formDataBodyString = "";
                    if(formDataBodyBuilder.length()>0){
                        formDataBodyString = formDataBodyBuilder.substring(0, formDataBodyBuilder.length() - 1);
                    }
                    /*
                     * get data bytes
                     */
                    byte[] bodyBytes =  formDataBodyString.getBytes(charset);
                    int contentLength = bodyBytes.length;
                    HttpHeaders httpHeaders = new HttpHeaders();
                    httpHeaders.putAll(exchange.getRequest().getHeaders());
                    httpHeaders.remove(HttpHeaders.CONTENT_LENGTH);
                    /*
                     * in case of content-length not matched
                     */
                    httpHeaders.setContentLength(contentLength);

                    /**
                     * validate request params or form data
                     */
                    Map<String, Object> bodyMap = StringUtils.isEmpty(formDataBodyString)?new HashMap<String, Object>():decodeFormBody(formDataBodyString);
                    Result checkResult = validParam(exchange, bodyMap);
                    if(checkResult.getCode()!=0){
                        return  errorInfo(exchange, checkResult.getCode(), checkResult.getMessage());
                    }
                    /*
                     * use BodyInserter to InsertFormData Body
                     */
                    BodyInserter<String, ReactiveHttpOutputMessage> bodyInserter = BodyInserters.fromObject(formDataBodyString);
                    CachedBodyOutputMessage cachedBodyOutputMessage = new CachedBodyOutputMessage(exchange, httpHeaders);
                    log.debug("[GatewayContext]Rewrite Form Data :{}",formDataBodyString);
                    return bodyInserter.insert(cachedBodyOutputMessage,  new BodyInserterContext())
                            .then(Mono.defer(() -> {
                                ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(
                                        exchange.getRequest()) {
                                    @Override
                                    public HttpHeaders getHeaders() {
                                        return httpHeaders;
                                    }
                                    @Override
                                    public Flux<DataBuffer> getBody() {
                                        return cachedBodyOutputMessage.getBody();
                                    }
                                };
                                ServerHttpResponse originalResponse = exchange.getResponse();
                                originalResponse.getHeaders().setContentType(MediaType.APPLICATION_JSON);
                                DataBufferFactory bufferFactory = originalResponse.bufferFactory();
                                ServerHttpResponseDecorator response = buildResponse(originalResponse, bufferFactory, (Map)checkResult.getResult());
                                return chain.filter(exchange.mutate().request(decorator).response(response).build());
                            }));

        });

    }

有时需要对返回的数据统一处理,那么可以通过封装ServerHttpResponseDecorator进行处理,ServerHttpResponse装饰器ServerHttpResponseDecorator,主要覆盖写入响应体数据缓冲区的部分。

    private ServerHttpResponseDecorator buildResponse(ServerHttpResponse originalResponse, DataBufferFactory bufferFactory, Map result) {
        return new ServerHttpResponseDecorator(originalResponse) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                System.out.println("++++++++++++++++++++++++1");
                if (getStatusCode().equals(HttpStatus.OK) && body instanceof Flux) {
                    Flux<? extends DataBuffer> fluxBody = Flux.from(body);
                    return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
                        DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                        DataBuffer join = dataBufferFactory.join(dataBuffers);
                        byte[] content = new byte[join.readableByteCount()];
                        join.read(content);
                        DataBufferUtils.release(join);
                        // 流转为字符串
                        String responseData = new String(content, Charsets.UTF_8);
                        System.out.println(responseData);

                        Map map = JSON.parseObject(responseData);
                        //处理返回的数据
                        
                        //To do

                       
                        byte[] uppedContent = responseData.getBytes(Charsets.UTF_8);
                        originalResponse.getHeaders().setContentLength(uppedContent.length);
                        return bufferFactory.wrap(uppedContent);
                    }));
                } else {
                    System.out.println("----------"+getStatusCode());
                }
                return super.writeWith(body);
            }

            @Override
            public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
                return writeWith(Flux.from(body).flatMapSequential(p -> p));
            }
        };
    }

更多接口、代码工具、开发资源请访问昂焱数据:https://www.ayshuju.com文章来源地址https://www.toymoban.com/news/detail-559622.html

到了这里,关于SpringCloud GateWay通过过滤器GatewayFilter修改请求或响应内容的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringCloud - Spring Cloud 之 Gateway网关,Route路由,Predicate 谓词/断言,Filter 过滤器(十三)

    阅读本文前可先参考 ​​​​​​SpringCloud - Spring Cloud根/父项目,开发准备(二)_MinggeQingchun的博客-CSDN博客 SpringCloud - Spring Cloud 之 Gateway网关(十三)_MinggeQingchun的博客-CSDN博客 Web 有三大组件(监听器 过滤器 servlet),Spring Cloud GateWay 最主要的功能就是路由转发,而在定义

    2024年02月14日
    浏览(67)
  • 【Java】SpringCloud Gateway自定义过滤器中获取ServerHttpRequest的body中的数据为NULL的问题

    这个情况出现在,我需要进行验证码的校验,因此用户的请求首先需要被验证码过滤器校验,而验证码过滤器不需要设定为全局过滤器,因此我就单纯的把它设定为了一个局部过滤器,代码如下 然后我进行请求的时候,json参数如下 然后请求经过解析后会发现,字符串居然是

    2024年02月09日
    浏览(53)
  • Gateway自定义过滤器——全局过滤器

    首先,我们要知道全局过滤器其实是特殊路由过滤器(特殊的GatewayFilter),会有条件地作用于所有路由。 为什么要自定义全局过滤器?就好比是看大门的保安大叔,平时主要是做好进出大门外来人员登记即可,但是因为新冠疫情,现在还需要给外来人员测量体温等等。而已有的

    2024年02月16日
    浏览(47)
  • Gateway网关 全局过滤器

    一、全局过滤器 全局过滤器GlobalFilter 全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。 区别在于GatewayFilter通过配置定义,处理逻辑是固定的。 需求:定义全局过滤器,拦截请求,判断请求的参数是否满足下面条件: 参数中是否有au

    2024年02月07日
    浏览(49)
  • gateway-过滤器执行顺序

    请求进入网关会碰到三类过滤器:当前路由过滤器、DefaultFilter、GlobalFilter。 请求路由后,会将当前路由过滤器和DefaultFilter、GlobalFilter,合并到一个过滤器链(集合)中,排序后依次执行每个过滤器 过滤器执行顺序 1.每一个过滤器都必须指定一个int类型的order值,order值越小

    2024年02月13日
    浏览(51)
  • 网关Gateway过滤器的使用

    前言: 最近在学习微服务相关的知识,看了黑马的相关课程,将关于Gateway过滤器的知识又总结了一些,希望能帮到各位小伙儿们以及加深下自己的印象🎊 如果文章有什么需要改进的地方还请大佬多多指教🥂 小威先感谢大家的支持了😁 Gateway网关的过滤器分为两种,一种是

    2023年04月09日
    浏览(48)
  • Spring Cloud Gateway 过滤器

    Spring Cloud Gateway 过滤器的种类有30多种。 官文文档地址: Spring Cloud Gateway https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories Spring Cloud Gateway大体可以分为下面两种类型的过滤器: 1、内置的过滤器         1.1、内置的局部过滤器         1.2、内置的全

    2024年03月28日
    浏览(59)
  • gateway过滤器没生效,特殊原因

    看这边文章的前提,你要会gateway,知道过滤器怎么配置? 直接来看过滤器,局部过滤器 再来看配置 请求路径 http://127.0.0.1:8080/appframework/services/catalog/catalogSpecials.json?pageindex=1pagesize=10pkid=d9873700ef7e42b3b8f4e782f345975b 看起来确实没什么问题 注意: 我这里还有个应用,就是网关转

    2024年02月14日
    浏览(52)
  • gateway之过滤器(Filter)详解

    在Spring Cloud中,过滤器(Filter)是一种关键的组件,用于在微服务架构中处理和转换传入请求以及传出响应。过滤器位于服务网关或代理中,并通过拦截请求和响应流量来提供各种功能。 过滤器在请求的不同生命周期阶段执行特定的操作,例如鉴权、认证、请求转发、限流、

    2024年02月05日
    浏览(43)
  • gateway过滤器中实现记录访问日志

    SpringCloud多服务项目环境,前端请求经过网关中转发到各个服务节点。日志中需要记录请求头中的部分参数、请求的body、响应状态及响应内容,并在请求头中新增一个标识。 PS: 1.Order 最高优先级。 2.Request Header 不可添加值,需重新创建后绑定。 3.Request Body IO流,读取一次后

    2024年02月15日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包