持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第16天,点击查看活动详情
16、路由配置
一、路由配置
1、简单路由
Spring Cloud 在 Zuul 的 routing 阶段实现了几个过滤器, 这些过滤器决定如何进行路由工作。其中, 最基本的就是 SimpleHostRoutingFilter,该过滤器运行后,会将 HTTP 请求全部转发到“源服务”( HTTP 服务), 本书将其称为简单路由,本章 7.2 节的例子实际上就是使用了简单路由进行请求转发。以下为简单路由的配置,同时使用了 path 与 url:
#配置简单路由
#配置简单路由
zuul.routes.routeTest.path=/routeTest/163
zuul.routes.routeTest.url=http://www.baidu.com
#配置简单路由 简化配置--只使用url
zuul.routes.routeTest163.url=http://www.baidu.com
为了简化配置,可以省略path,默认情况下使用routeId 作为 path
访问http://localhost:8080/routeTest/163 http://localhost:8080/routeTest163 都可以路由到163网站。
实际上,要触发简单路由,配置的 url 值需要以 http:或者 https:字符串开头。以下的配置不能触发简单路由:
zuul.routes.noRoute163.url=www.baidu.com
简单路由的过滤器 SimpleHostRoutingFilter 使用 HttpClient 进行转发,该过滤器会将HttpServletRequest 的相关数据(HTTP 方法、参数、请求头等)转换为 HttpClient 的请求 实例(HttpRequest), 再使用 CloseableHttpClient 进行转发。 在此过程中,为了保证转发的性能,使用了 HttpClient 的连接池功能。涉及连接池,就需要对其进行配置。在使用简单路由时,可以配置以下两项,修改 HttpClient 连接池的属性。
- zuul.host.maxTotalConnections:目标主机的最大连接数,默认值为200,配置该项,相当于调用了PoolingHttpClientConnectionManager的setMaxTotal方法
- zuul.host.maxPerRouteConnections:每个主机的初始连接数,默认值为20,配置该项,相当于调用了PoolingHttpClientConnectionManager的setDefaultMaxPerRoute方法
# 简单路由配置HttpClient转发连接池 。目标主机的最大连接数,默认值为200
zuul.host.maxTotalConnections=200
# 简单路由配置HttpClient转发连接池 。每个主机的初始连接数,默认值为20
zuul.host.maxPerRouteConnections=20
浏览SimpleHostRoutingFilter的run() -- 简单路由相当于请求转发
@Override
public Object run() {
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();//获取request
MultiValueMap<String, String> headers = this.helper
.buildZuulRequestHeaders(request);
MultiValueMap<String, String> params = this.helper
.buildZuulRequestQueryParams(request);
String verb = getVerb(request);
InputStream requestEntity = getRequestBody(request);
if (request.getContentLength() < 0) {
context.setChunkedRequestBody();
}
String uri = this.helper.buildZuulRequestURI(request);
this.helper.addIgnoredHeaders();
try {
//最终调用httpclient进行转发,为了保证转发的性能,会使用httpclient的连接池功能,如果涉及连接池则需要进行配置,上面有所提及
CloseableHttpResponse response = forward(this.httpClient, verb, uri, request,
headers, params, requestEntity);
setResponse(response);
}
catch (Exception ex) {
throw new ZuulRuntimeException(ex);
}
return null;
}
2、跳转路由
除了简单路由外,也支持跳转路由。当外部访问网关的A地址时,会跳转到B地址, 处理跳转路由 的过滤器为 SendForwardFilter 。接 下来进行简单测试,为网关项目 ( zuul-gateway )添加一个控制器
//跳转路由 - 测试控制器
@RestController
public class SourceController {
@RequestMapping(value = "/source/hello/{name}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String hello(@PathVariable("name") String name) {
return "Hello " + name;
}
}
控制器中提供了一个最简单的 hello 服务,用来当作“源服务”,在 application.yml 进行转发配置,配置项如下: 这里只是本地跳转 -- 不通端口的跳转不知道怎么配置,没找到
#跳转路由
zuul.routes.helloRoute.path=/test/**
zuul.routes.helloRoute.url=forward:/source/hello
当外部访问 /test 地址时,将会自动跳转型 /source/hello 地址。 打开浏览器,输入 http: // localhost: 8080/test/anugs ,可以看到浏览器会返回字符串 hello angus ,可见源服务被调用。跳转路由实现较为简单, 实际上是调用了 RequestDispatcher的 forwar 方法进行跳转。
浏览SendForwardFilter的run() -- 相当于重定向
@Override
public Object run() {
try {
RequestContext ctx = RequestContext.getCurrentContext();
String path = (String) ctx.get(FORWARD_TO_KEY);
//访问A,实际跳转B
//使用RequestDispatcher
RequestDispatcher dispatcher = ctx.getRequest().getRequestDispatcher(path);
if (dispatcher != null) {
ctx.set(SEND_FORWARD_FILTER_RAN, true);
if (!ctx.getResponse().isCommitted()) {
//直接forward跳转,过程中没有其他复杂处理
//简单路由是由网关响应,跳转路由由转向后的目标响应
dispatcher.forward(ctx.getRequest(), ctx.getResponse());
ctx.getResponse().flushBuffer();
}
}
}
catch (Exception ex) {
ReflectionUtils.rethrowRuntimeException(ex);
}
return null;
}
3、Ribbon 路由
我们己经接触过 Ribbon 路由。当网关作为 Eureka 客户端注册到 Eureka服务器时,可以通过配置 serviceId 将请求转发到集群的服务中。 使用以下配置,可以执行Ribbon 路由过滤器:
#配置 ribbon 路由规则
#zuul.routes.sale.path=/sale/**
#zuul.routes.sale.service-id=invoker-server
#配置 ribbon 路由规则 -- 省略配置
#zuul.routes.invoker-server.path=/sale/**
#配置 ribbon 路由规则
zuul.routes.sale.path=/sale/**
zuul.routes.sale.url=invoker-server
与简单路由类似, serviceId 也可以被省略。当省略时,将会使用 routeld 作为 serviceld 下面的配置片断,效果等同于上面的配置:
#配置 ribbon 路由规则 -- 省略配置
#zuul.routes.invoker-server.path=/sale/**
需要注意的是,如果提供的url配置项不是简单路由格式(不以 http :或 https;开头), 也不是跳转路由格式( forward:开头),那么将会执行 Ribbon 路由过滤器,将url看作 serviceId。 下面的配置片断,效果也等同于前面的配置:
#配置 ribbon 路由规则
zuul.routes.sale.path=/sale/**
zuul.routes.sale.url=invoker-server
4、自定义路由规则
如果上面的路由配置无法满足实际需求,可以考虑使用自定义的路由规则 。实现方式 较为简单,在配置类中创建一个 PatternServiceRouteMapper 即可
@Configuration
public class MyConfig {
@Bean
public PatternServiceRouteMapper patternServiceRouteMapper() {
// 通过一个正则表达式来匹配
return new PatternServiceRouteMapper("(zuul)-(?<module>.+)-(service)",
"${module}/**");
}
}
创建了 PatternServiceRouteMapper 实例,构造器的第一个参数为 serviceId 的正则表达 式,第二个参数为路由的 path。 访问 module/** 的请求,将会被路由到 zuul-module-service的微服务
更进一步,以上的路由规则,如果想让一个或多个服务不被路由,可以使用zuul .ignoredServices 属性。 例如在代码清单 7-6 的基础上,想排除 zuul-sale-service、
zuul-book-service 这两个模块,可以配置 zuul.ignoredServices: zuul-sale-service, zuul-bookservice。
zuul.ignoredServices: zuul-sale-service, zuul-bookservice
5、忽略路由
除了 上面提到的 zuul.ignoredServices 配置可以忽略路由外,还可以使用zuul.i gnoredPattens 来设置不进行路由的 URL, 请见以下配置片断:
#配置 ribbon 路由规则
zuul.routes.sale.path=/sale/**
zuul.routes.sale.service-id=invoker-server
#配置忽略路由
zuul.ignored-patterns=/sale/router/3
zuul.ignoredPatterns=/sale/noRoute
访问/sale路径的请求都会被路由到 invoker-server 进行处理 但是 /sale/noRoute 和 /sale/router/3 除外, http://localhost:8080/sale/router/2 就可以正常返回
通配符
详细请见:www.jb51.net/article/127…