Search code examples
javaspringspring-bootspring-webfluxspring-cloud-gateway

Spring Gateway how to get originResponseHeaders And replace proxy html content?


I want ot use Spring gateway proxy HTML webpage And replace some text,

Config like:

spring:
  cloud:
    gateway:
      routes:
      - id: replace_route
        uri: http://my-web-site-article/
        predicates:
        - Path=/article/**
        filters:
        - ReplaceText

In my filter , I want to judge the 'origin response content-type', And modify if the Content-Type is html text. But I found the Content-Type is alway null . In zuul gateway I can use RequestContext.getCurrentContext().getOriginResponseHeaders(); Is there something similar in Spring Cloud Gateway ? Could you provide sample code for reference ? Many thanks! This question has puzzled me for a long time.

my code :

@Component
@Slf4j
public class ModifyGatewayFilterFactory extends ModifyRequestBodyGatewayFilterFactory {
       
        HttpHeaders headers = exchange.getResponse().getHeaders();
        List<String> strings = headers.get("Content-Type");
        // [Content-Type alway null why ?] 
        
        // boolean html = strings.contains("text/html")

        //TODO:   if html (not pic,binaryFile) , Then modify and replace some text

}

In Zuul gateway code is :

   @Override
    public boolean shouldFilter() {
        boolean isHtml = RequestContext.getCurrentContext().getOriginResponseHeaders().getContentType()..;
        return isHtml;
    }


    @Override
    public Object run() {
        RequestContext context = getCurrentContext();
        InputStream stream = context.getResponseDataStream();
        if (stream == null) {
            log.info("stream==null !!!");
            return null;
        }

// decompression
        stream = context.getResponseGZipped() ? new GZIPInputStream(stream) : stream;

        String body = StreamUtils.copyToString(stream, StandardCharsets.UTF_8);

// modify HTML Content
        HttpServletRequest request = context.getRequest();

        body = modifyBody2(request, body);

// compress gzip
        ByteArrayOutputStream bos = new ByteArrayOutputStream(body.length());
        GZIPOutputStream gzip = new GZIPOutputStream(bos);
        gzip.write(body.getBytes(StandardCharsets.UTF_8));
        gzip.close();
        byte[] compressed = bos.toByteArray();
        bos.close();
        context.setResponseDataStream(new ByteArrayInputStream(compressed));
        return null;
    }

Solution

  • I finally found a solution,This code is work for me.

    The point is to get parameters in getRewriteFunction. This is easy to do by extends ModifyResponseBodyGatewayFilterFactory

    /**
     * ref:<a href="https://juejin.cn/post/6933172840938078215">ref</a>
     *
     * @author donald
     * @date 2021/02/24
     */
    @Slf4j
    @Component
    public class CustomerModifyResponseGatewayFilterFactory extends ModifyResponseBodyGatewayFilterFactory {
        @Override
        public GatewayFilter apply(Config config) {
            return new ModifyResponseGatewayFilter(this.getConfig());
        }
    
        private Config getConfig() {
            Config config = new Config();
            config.setRewriteFunction(byte[].class, byte[].class, getRewriteFunction());
            return config;
        }
    
    
        private RewriteFunction<byte[], byte[]> getRewriteFunction() {
            return (exchange, resp) -> {
    
                ServerHttpResponse response = exchange.getResponse();
    
                String contentType = response.getHeaders().getFirst("Content-Type");
    
                //todo:gzip,
                if (contentType !=null &&contentType.contains(MediaType.TEXT_HTML_VALUE)){
                    String html = "modify-html";
                    return Mono.just(html.getBytes(StandardCharsets.UTF_8));
                }else {
                    return Mono.just(resp);
                }
    
              
            };
        }
    }