1.传统路由配置
通过在配置文件中具体指定每个路由表达式与服务实例的映射关系来实现API网关对外部请求的路由。
单实例配置:通过一组zuul.routes.<route>.path与zuul.routes.<route>.url参数对的方式配置,比如:
zuul.routes.user-service.path=/user-service/** zuul.routes.user-service.url=http://localhost:8080/
多实例配置:通过一组zuul.routes.<route>.path与zuul.routes.<route>.serviceId参数对的方式配置,比如:
zuul.routes.user-service.path=/user-service/** zuul.routes.user-service.serviceId=user-service
但是在实际微服务架构设计中,寄宿在网关下的微服务数量比较多,在网关配置文件中一个个的加上如上所示的路由配置会非常繁琐,所以这里引入“网关白名单”概念
2.动态路由-“服务白名单”
gateway.properties
中配置服务白名单
xxx.includes=\ serviceName1,\ serviceName2,\ serviceName3
定义
NamespaceDiscoveryClient
类继承DiscoveryClient
,重写getServices()
方法,获取白名单服务列表和服务发现注册中心(consul)服务列表的交集
@Overridepublic List<String> getServices() { // 获取白名单服务集合 Set<String> services = StringUtils.commaDelimitedListToSet(env.getProperty("xxx.includes", "")); // client.getServices()获取服务发现中服务集合 // retainAll() 集合取交集 services.retainAll(client.getServices()); return new ArrayList<>(services); }
主类
GatewayApp
@EnableZuulProxy@EnableDiscoveryClient@SpringBootApplication@EnableFeignClientspublic class GatewayApp { public static void main(String[] args) { SpringApplication.run(GatewayApp.class, args); } @Autowired private Environment env; @Autowired private DiscoveryClient discovery; // 服务路由适配 // user-service -> user/service @Bean public ServiceRouteMapper serviceRouteMapper() { return new ServiceRouteMapper() { @Override public String apply(String serviceId) { return StringUtils.replaceChars(serviceId, '-', '/'); } }; } // 初始化路由器过滤bean @Bean public GateWayFilter filter() { String url = env.getProperty("xxx.filter", ""); return new GateWayFilter(url); } @Bean public DiscoveryClientRouteLocator discoveryRouteLocator(ServerProperties server, ZuulProperties zuulProperties) { DiscoveryClient discovery = new NamespaceDiscoveryClient(this.env, this.discovery); return new DiscoveryClientRouteLocator(server.getServletPrefix(), discovery, zuulProperties, serviceRouteMapper()) { protected LinkedHashMap<String, ZuulRoute> locateRoutes() { LinkedHashMap<String, ZuulRoute> routes = super.locateRoutes(); for (ZuulRoute route : routes.values()) { route.setStripPrefix(false); } return routes; } }; } }
DiscoveryClient discovery = new NamespaceDiscoveryClient(this.env, this.discovery);
初始化前面自定义的NamespaceDiscoveryClient
LinkedHashMap<String, ZuulRoute> routes = super.locateRoutes();
调用父类DiscoveryClientRouteLocator
的locateRoutes()
方法父类
DiscoveryClientRouteLocator
中,对白名单和服务注册中心服务交集,进行类似zuul.routes.user-service.path=/user-service/**,zuul.routes.user-service.serviceId=user-service
的拼接和构造
@Override protected LinkedHashMap<String, ZuulRoute> locateRoutes() { LinkedHashMap<String, ZuulRoute> routesMap = new LinkedHashMap<String, ZuulRoute>(); routesMap.putAll(super.locateRoutes()); if (this.discovery != null) { Map<String, ZuulRoute> staticServices = new LinkedHashMap<String, ZuulRoute>(); for (ZuulRoute route : routesMap.values()) { String serviceId = route.getServiceId(); if (serviceId == null) { serviceId = route.getId(); } if (serviceId != null) { staticServices.put(serviceId, route); } } // Add routes for discovery services by default // 这里的services集合是取出的白名单和服务注册中心的交集 List<String> services = this.discovery.getServices(); String[] ignored = this.properties.getIgnoredServices() .toArray(new String[0]); for (String serviceId : services) { // Ignore specifically ignored services and those that were manually // configured String key = "/" + mapRouteToService(serviceId) + "/**"; if (staticServices.containsKey(serviceId) && staticServices.get(serviceId).getUrl() == null) { // Explicitly configured with no URL, cannot be ignored // all static routes are already in routesMap // Update location using serviceId if location is null ZuulRoute staticRoute = staticServices.get(serviceId); if (!StringUtils.hasText(staticRoute.getLocation())) { staticRoute.setLocation(serviceId); } } if (!PatternMatchUtils.simpleMatch(ignored, serviceId) && !routesMap.containsKey(key)) { // Not ignored routesMap.put(key, new ZuulRoute(key, serviceId)); } } } if (routesMap.get(DEFAULT_ROUTE) != null) { ZuulRoute defaultRoute = routesMap.get(DEFAULT_ROUTE); // Move the defaultServiceId to the end routesMap.remove(DEFAULT_ROUTE); routesMap.put(DEFAULT_ROUTE, defaultRoute); } LinkedHashMap<String, ZuulRoute> values = new LinkedHashMap<>(); for (Entry<String, ZuulRoute> entry : routesMap.entrySet()) { String path = entry.getKey(); // Prepend with slash if not already present. if (!path.startsWith("/")) { path = "/" + path; } if (StringUtils.hasText(this.properties.getPrefix())) { path = this.properties.getPrefix() + path; if (!path.startsWith("/")) { path = "/" + path; } } values.put(path, entry.getValue()); } return values; }
过滤后的route进行处理,在配置文件中,设置了默认路由前缀
zuul.servletPath=/services
,所以设置route.setStripPrefix(flase)
关闭移除代理前缀的动作。
for (ZuulRoute route : routes.values()) { route.setStripPrefix(false); }
作者:angeChen
链接:https://www.jianshu.com/p/d924a090a1ba
共同學習,寫下你的評論
評論加載中...
作者其他優質文章