跳到主要内容

08、SpringCloud Gateway 拦截转发

1、 application.yml配置;

spring:
  cloud:
    gateway:
      routes:
      - id: remoteaddr_route
        uri: http://localhost:8080
        predicates:
          - Path=/test
        filters:
          - RewritePath=/test, /add
          - Test

参数解析:

predicates:当满足predicates下的条件时,即path路径为/test时网关生效。

uri:跳转到uri(注意:此处为uri不是url)。

filters:filters 下的RewritePath会将路径重定义将/test换为/add。若不加此处就会将path所带路径自动拼接到uri后面。

最后一行的- Test 是文件名,下面会写到

2、 网关实现;

网关的主要实现由Filter,Mono,GatewayFilterFactory三部分组成。

解析:

GatewayFilterFactory:上面的-Test的文件名就是此处的名称应为TestGatewayFilterFactory,网关匹配时会自动忽略后面的GatewayFilterFactory,从而通过Test找到TestGatewayFilterFactory。

@Component
@Slf4j
@Lazy
public class TestGatewayFilterFactory extends AbstractGatewayFilterFactory {
    @Autowired
    TestFilter TestFilter;

    @Override
    public GatewayFilter apply(Object config) {
        return TestFilter;
    }
}

Filter:相当于一个中间层

@Component
public class TestFilter implements GatewayFilter, Ordered {
    @Autowired
    TestMono TestMono;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        return TestMono.testMono(exchange, chain);
    }

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

Mono:主要的逻辑实现层

主要实现由testMono来协调,网关转发的请求的解析在此方法内实现,若有解密需求在此方法内添加方法即可。

requestDecorator:此方法用于请求的转换,代码中实现的是将post请求转为get。

urlEncodeUTF8:在此代码的实现中用于解析post请求的参数将其拼接到get请求中。

responseDecorator:网关处理完毕后返回的结果将在这里包装后输出,若有加密在此方法内执行。

@Component
@Slf4j
public class TestMono {

//主方法
public Mono<Void> testMono(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        return DataBufferUtils.join(request.getBody())
                .flatMap(dataBuffer -> {
                    DataBufferUtils.retain(dataBuffer);
                    byte[] bytes = new byte[dataBuffer.readableByteCount()];
                    dataBuffer.read(bytes);
                    //释放掉内存
                    DataBufferUtils.release(dataBuffer);
                    String body = new String(bytes, StandardCharsets.UTF_8);
                    URI url = request.getURI();
                    log.info("url: {}", url);
                    JSONObject bodyJson = JSON.parseObject(body);
                    JSONObject innerBody = bodyJson.getJSONObject("BODY");

                    return chain.filter(exchange.mutate().request(requestDecorator(request, innerBody)).response(responseDecorator(response)).build());
                });
    }

//将post请求转换成get(若是get可连同下面的方法省略)
    private static ServerHttpRequestDecorator requestDecorator(ServerHttpRequest request, JSONObject body) {
        return new ServerHttpRequestDecorator(request) {
            // 重新设置http method
            @Override
            public HttpMethod getMethod() {
                return HttpMethod.GET;
            }

            @Override
            public String getMethodValue() {
                return "GET";
            }

            // 转换请求参数
            @Override
            public URI getURI() {
                String params = urlEncodeUTF8(body);
                return URI.create(request.getURI() + "?" + params);
            }
        };
    }

    /**
     * 转换urlparam
     *(post请求忽略)
     * @param jsonObject
     * @return
     */
    private static String urlEncodeUTF8(JSONObject jsonObject) {
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
            if (sb.length() > 0) {
                sb.append("&");
            }
            sb.append(String.format("%s=%s",
                    entry.getKey(),
                    entry.getValue()
            ));
        }
        log.info("format param: {}", sb);
        return sb.toString();
    }
//网关转出
    private ServerHttpResponseDecorator responseDecorator
            (ServerHttpResponse response) {
        return new ServerHttpResponseDecorator(response) {

            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (body instanceof Flux) {
                    Flux<? extends DataBuffer> flux = Flux.from(body);
                    return super.writeWith(flux.buffer().map(dataBuffers -> {
                        DataBufferFactory dataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
                        StringBuilder sb = new StringBuilder("");
                        DataBuffer join = dataBufferFactory.join(dataBuffers);
                        byte[] bytes = new byte[join.readableByteCount()];
                        join.read(bytes);
                        DataBufferUtils.release(join);
                        String s = new String(bytes, StandardCharsets.UTF_8);
                        sb.append(s);
                        //去掉字符串最外层的[]
                        //sb.deleteCharAt(0).deleteCharAt(sb.length() - 1);
                        // 构造返回报文
                        JSONObject jsonBody = JSON.parseObject(sb.toString(), JSONObject.class, Feature.OrderedField);
                        String content = JSON.toJSONString(jsonBody, SerializerFeature.WRITE_MAP_NULL_FEATURES, SerializerFeature.QuoteFieldNames, SerializerFeature.PrettyFormat);
                        byte[] contentByte = content.getBytes();
                        // 重置content-length
                        response.getHeaders().setContentLength(contentByte.length);
                        return response.bufferFactory().wrap(contentByte);
                    }));
                }
                return super.writeWith(body);
            }
        };
    }
}

Spring cloud gateway学习地址:Spring Cloud Gateway 2.1.0 中文官网文档 - 云+社区 - 腾讯云

版权声明:「DDKK.COM 弟弟快看,程序员编程资料站」本站文章,版权归原作者所有