需求是这样的, 公司可以让第三方开发应用 , 会生成一个外网域名例如(xxx.xxx.com), 但是需要对这些域名进行访问权限控制,实现思路是使用 spring cloud gateway ,通过通配符配置 将所有应用域名的入口放在gateway 上, 然后再访问对应域名内网地址, 外网内网地址区别是主域不同 内网(xxx.xxxinner.com)

实现方式 使用 gateway 提供 path predicate 拦截所有请求,然后在转发到内网地址。 因为 path predicate 指定了url 后不能动态修改,可以中间添加自定义拦截处理。

gateway PathRoutePredicateFactory 实现方式是:

RoutePredicateHandlerMapping ForwardPathFilter 设置 ROUTE getHandlerInternal 方法内 设置 request path 后面会转发 RoutePredicateHandlerMapping ForwardPathFilter

查看 ForwardPathFilter 的源码发现 他数执行顺序 是0

加一个自定义的 globalFilter 替换掉 GATEWAY_ROUTE_ATTR 实现外网 转内网地址

/**
 * 自定义拦截
 */
public class ReplaceAccessUrlFilter implements GlobalFilter, Ordered {

    private static Logger log = LoggerFactory.getLogger(RepalceAccessUrlFilter.class);


    @Value("${application.replace-domain}")
    private String replaceDomain;

    @Value("${application.inner-domain}")
    private String innerDomain;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        URI uri = exchange.getRequest().getURI();
        //外网地址替换成内网访问,
        String routePath = "http://" + (uri.getHost().replace(replaceDomain, innerDomain));
        try {
            log.debug("转化访问地址:{} , {} ", routePath, uri.getPath());
            URI routeUri = new URI(routePath);
            Route oldRoute = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
            Route route = Route.async().predicate((key) -> true).id(oldRoute.getId()).uri(routeUri).build();
            exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, route);
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }

        return chain.filter(exchange);
    }


    @Override
    public int getOrder() {
        return 201;
    }


}

Path 配置

    @Bean
    public RouteLocator routeLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("replace", r ->
                        r.path("/**").uri("http://xxx.com"))
                .build();
    }

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐