Gateway网关和Feign调用开启gzip压缩

总监:咳咳咳…小王啊,最近挺清闲啊!

我:没有没有,还有好多bug没改呢。

总监:有个需求需要你弄一下。

我:好的好的。(摸鱼被抓不敢反抗啊!!!)

总监:现在的数据响应我觉得还可以提升一下,你把所有的响应在响应前都压缩一遍。还有服务之间feign调用的形式。

我:好的好的,现在就干。

总监:晚上给我个demo!


一:GateWay网关实现数据压缩

思路:
  1. 要网关吐出压缩后的数据,则要实现一个网关拦截器,在最后一层的拦截器当中修改响应的数据。
  2. 查看浏览器请求头中的Accept-Encoding: gzip, deflate一项,这里使用gzip压缩。

好啦,既然没有那么复杂,就开始干吧。


import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.log4j.Log4j2;
import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.zip.GZIPOutputStream;


@Configuration
@Log4j2
public class ResponseFilter implements GlobalFilter, Ordered {

    /**
     * 约定的压缩格式
     */
    private final static String GZIP = "gzip";


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //获取响应体
        ServerHttpResponse originalResponse = exchange.getResponse();
        //获取请求体
        ServerHttpRequest request = exchange.getRequest();
        DataBufferFactory bufferFactory = originalResponse.bufferFactory();
        ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (body instanceof Flux) {
                    Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) 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 responseString = new String(content, Charset.forName("UTF-8"));
                        //判断该浏览器是否支持gzip解码,如果支持gzip解码,则进行压缩
                        String acceptEncoding = request.getHeaders().getFirst("Accept-Encoding");
                        if(!StrUtil.hasBlank(acceptEncoding)){
                            assert acceptEncoding != null;
                            //是否支持压缩
                            if(acceptEncoding.contains(GZIP)){
                                //支持压缩
                                ByteArrayOutputStream bout = new ByteArrayOutputStream();
                                //压缩输出流中的数据
                                GZIPOutputStream gout;
                                try {
                                    gout = new GZIPOutputStream(bout);
                                    gout.write(content);
                                    gout.close();
                                    content = bout.toByteArray();
                                    originalResponse.getHeaders().setContentLength(content.length);
                                    originalResponse.getHeaders().set("content-encoding", GZIP);
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }else{
                                originalResponse.getHeaders().setContentLength(responseString.getBytes().length);
                            }
                        }
                        return bufferFactory.wrap(content);
                    }));
                }
                return super.writeWith(body);
            }
        };
        return chain.filter(exchange.mutate().response(decoratedResponse).build());
    }

    @Override
    public int getOrder() {
        return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 2;
    }

}

好啦,代码撸完啦!试一下通过网关请求下游服务是否返回了压缩的数据。

ok!网关搞定啦,接下来feign就简单了!

二:Feign之间调用实现gzip压缩

只需要在yaml配置文件中增加如下配置:

#feign开启gzip压缩配置
feign:
  compression:
    request:
      enabled: true
      mime-types: ["text/xml,application/xml,application/json"]
      min-request-size: 2048
    response:
      enabled: true

开启debug级别的日志,服务之间调用一下可以看到已经开启了gzip。


我:嘿嘿,全部搞定。晚上才提交,又可以开心的划水了。

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
在使用 Feign 进行服务调用时,通常需要在 Spring Boot 应用中配置 FeignClient 接口的实现类。而在 Spring Cloud Gateway 中,我们可以通过配置一个 Filter 来实现 FeignClient 的调用。 具体步骤如下: 1. 首先,在 pom.xml 文件中加入 Feign 的依赖: ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> ``` 2. 在应用程序的启动类上添加 `@EnableFeignClients` 注解,以启用 Feign 客户端功能。 ```java @SpringBootApplication @EnableFeignClients public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } } ``` 3. 创建一个 FeignClient 接口,用于定义需要调用的服务。例如: ```java @FeignClient(name = "test-service") public interface TestClient { @GetMapping("/hello") String hello(); } ``` 4. 创建一个 Filter,用于将请求转发给 FeignClient 接口。例如: ```java @Component public class FeignFilter implements GlobalFilter, Ordered { private final TestClient testClient; public FeignFilter(TestClient testClient) { this.testClient = testClient; } @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { String result = testClient.hello(); ServerHttpResponse response = exchange.getResponse(); response.setStatusCode(HttpStatus.OK); response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); byte[] bytes = result.getBytes(StandardCharsets.UTF_8); DataBuffer buffer = response.bufferFactory().wrap(bytes); return response.writeWith(Flux.just(buffer)); } @Override public int getOrder() { return -1; } } ``` 在这个 Filter 中,我们注入了上面定义的 TestClient 接口,并在 filter 方法中调用了该接口的 hello 方法。最后,我们将返回的结果写回给客户端。 5. 在 application.yml 文件中添加 FeignClient 的配置: ```yaml spring: application: name: gateway feign: client: config: default: loggerLevel: full ``` 在这个配置中,我们将 FeignClient 的日志级别设置为 `full`,以方便调试。 6. 启动应用程序,并访问 Gateway 的 URL,即可看到 FeignClient 的调用结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值