2022年8月更文挑战2-springcloudgateway进行请求地址转发

761 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情

springcloudgateway进行请求地址转发

前文

本文内容为在使用springcloud的过程中,当需要对于请求的地址进行特殊的处理时,一种路由方案的处理。

具体方案

该方案主要是应用网关服务中gateway的特性进行处理,自定义一个过滤器并实现全局的过滤器。在过滤器中,我们要处理的核心对象则是exchange对象。而exchange对象本身则是网关用来处理请求的核心组件,其中包含了若干请求及响应的信息。而当我们想要把请求进行转发时,可能很容易想到将exchange中的request对象进行重新处理,利用新地址进行request对象的构建。但经过尝试,仅仅按照request=exchange.getRequest().mutate().path(newReqPath).build();重新构建对象,实际访问的地址依然是我们本来所填写的,并不能实现请求地址的转发功能。经过对于请求内容的比较,以及相关文档的查询,其实我们需要处理的是exchange中的属性,gatewayRequestUrl。这个属性才是实际在请求进行调用时,我们所采用的请求地址。因此进行请求转发的核心操作是需要进行该属性内容的变更,也就是如下的代码:

exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR,URI.create(newPath));

经过上述操作,即可将当前请求根据需要路由到我们所需要的请求地址当中。具体的原理还请查看源码了解。

完整的代码实现逻辑如下,核心部分也就是上述的内容。

public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    // 该步骤可选。可以传递给下游服务器,⽤于业务处理
    ServerHttpRequest requestBase = exchange.getRequest();
    ServerWebExchangeUtils.addOriginalRequestUrl(exchange,requestBase.getURI());
    ServerHttpRequest request;
    String basePath = null;
    String newReqPath = null;
    Boolean needChange = false;
    for (int i = 0; i < this.gatewayFilterProperties.getBaseUrl().size(); i++) {
        basePath = this.gatewayFilterProperties.getBaseUrl().get(i);
        if(basePath.equals(requestBase.getPath().value())){
            if(this.gatewayFilterProperties.getNewUrl().size() > i){
                newReqPath = this.gatewayFilterProperties.getNewUrl().get(i);
            }else{
                newReqPath = basePath;
            }
            needChange = true;
            break;
        }
    }
    if(needChange){
        String newPath = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR).toString().replace(basePath,newReqPath);
        request = exchange.getRequest().mutate().path(newReqPath)
            .build();
        exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR,URI.create(newPath));
        ServerWebExchange build = exchange.mutate().request(request).build();
        return chain.filter(build);
    }else {
        return chain.filter(exchange);
    }
}