springcloud 服务网关,springcloud网关
00-1010一、祖尔二简介。请求路由2.1传统路由2.2面向服务的路由三。路由规则3.1默认路由规则3.2自定义路由规则IV。祖尔滤波器与设置保险丝VI。实战6.1 pom文件6.2配置文件6.3过滤器配置6.4保险丝配置6.5启动类
00-1010Zuul作为微服务系统的网关组件,用于搭建边缘服务,致力于动态路由、过滤、监控、弹性伸缩和安全。它在微服务架构中起着重要的作用,主要表现在以下六个方面:
Zull、Ribbon和Eureka的结合可以实现智能路由和负载均衡的功能。Zull可以根据一定的策略将请求分发到不同的实例;
网关作为一个边界服务,聚合了内部服务的API接口,统一对外公开接口。保护内部服务的API接口,防止内部服务被外界调用泄露敏感信息;
网关可以认证用户的身份和权限,防止非法请求API接口;
网关可以实现监控功能,输出实时日志,记录请求;
网关可用于监控流量,并在高流量的情况下降低服务质量;
API与内部服务分离,方便测试。
00-1010使用Spring Cloud Zuul实现路由的规则非常简单。有两条路线:传统路线和面向服务的路线。
00-1010让我们看看以下配置:
zuul . routes . holiday . path=/holiday/** zuul . routes . holiday . URL=http://本地主机:8080/该规则配置意味着所有符合/holiday/* *规则的访问都将被路由转发到3358本地主机33608080/address,例如当我们访问http://localhost33605555/holiday/getalldays时,API网关会将请求转发到http://localhost 33提供的微服务接口Holiday是微服务的名称,可以任意定义,但是一组路径和url映射关系的路由名称必须相同,下面的面向服务的路由方法也是一样的。
目录
春云Zuul和春云尤里卡可以实现无缝连接,实现面向服务的路由。我们将路由的路径映射到特定的服务,特定的url由Eureka的服务发现机制自动维护。具体配置如下(其他配置参考下面实战):
zuul . routes . holiday . path=/holiday/* * zuul . routes . holiday . service-id=holiday通过上面的配置,我们不需要维护具体实例的位置,所以维护非常简单。此外,面向服务的路由默认实现负载均衡,而传统路由需要手动添加所有实例的位置。
一、Zuul简介
春云Zuul提供默认路由规则。当然,我们也可以修改这个路由规则。
00-1010 Zull配合Eureka使用后,Zull会默认配置一个路由规则,这些默认规则的路径会使用service-id配置的服务名作为请求的前缀。例如,如果有假日服务,其默认规则如下
zuul . routes . holiday . path=/holiday/* * zuul . routes . holiday . service-id=holiday。默认情况下,Eureka上的所有服务都会被Zuul自动创建的映射关系路由,这就使得一些我们不想对外开放的服务也会被外部访问。这时我们可以配置zuul.ignored-services参数设置一个服务名匹配表达式来判断。如果服务名与表达式匹配,Zull将跳过这个服务,并且不为它创建路由规则。例如:zuul.ignored-services=*表示不会自动为所有服务创建路由规则,所以我们需要为每个服务配置路由规则。
00-1010有这样一个场景,由于业务拓展和版本升级,出现了不同版本的服务。比如我们有这样的名字:holiday-v1,holiday-v2。默认情况下,Zuul自动为带有服务名前缀的服务创建路由表达式。对于holiday-v1,生成了/holiday-v1和/holiday-v2两条路径进行映射,但是生成的表达式规则比较简单,不利于路径规则的管理。
通常,对于上述情况,我们希望生成的路径是/
v1/holiday,/v2/holiday。我们可以通过自定义路由规则来实现,具体代码如下:
@Beanpublic PatternServiceRouteMapper serviceRouteMapper(){ return new PatternServiceRouteMapper( "(?<name>^.+)-(?<version>v.+$)", "${version}/${name}");}
PatternServiceRouteMapper对象可以让开发者通过正则表达式来自定义服务于路由映射的生成关系。
四、Zuul的过滤器
Zull有请求过滤的功能,其过滤器可以在Http请求的发起和响应返回期间执行一系列的过滤器。
Zuul包扩以下四种过滤器:
PRE
:该类型的filters在Request routing到源web-service之前执行。可以进行一些权限认证,日志记录,或者额外给Request增加一些属性供后续的filter使用;ROUTING
:该类型的filters用于把Request routing到源web-service,源web-service是实现业务逻辑的服务。这里使用HttpClient请求web-service;POST
:该类型的filters在ROUTING返回Response后执行。用来实现对Response结果进行修改,收集统计数据以及把Response传输会客户端;ERROR
:上面三个过程中任何一个出现错误都交由ERROR类型的filters进行处理。Zuul过滤器具有以下关键特性:
Type(类型)
:Zuul过滤器的类型,这个类型决定过滤器在哪个阶段执行,例如:pre,post等阶段;Execution Order(执行顺序)
:规定了过滤器的执行顺序,Order的值越小,越先执行;Criteria(标准)
:Filters执行所需条件Action(行动)
:如果符合执行条件,则执行Action(具体逻辑代码)示例如下:
public class MyFilter extends ZuulFilter { @Override public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); System.out.println(String.format("%s AccessUserNameFilter request to %s", request.getMethod(), request.getRequestURL().toString())); // 获取请求的参数 String username = request.getParameter("username"); // 如果请求的参数不为空,且值为chhliu时,则通过 if(null != username && username.equals("chhliu")) { // 对该请求进行路由 ctx.setSendZuulResponse(true); ctx.setResponseStatusCode(200); // 设值,让下一个Filter看到上一个Filter的状态 ctx.set("isSuccess", true); return null; }else{ // 过滤该请求,不对其进行路由 ctx.setSendZuulResponse(false); // 返回错误码 ctx.setResponseStatusCode(401); // 返回错误内容 ctx.setResponseBody("{"result":"username is not correct!"}"); ctx.set("isSuccess", false); return null; } } @Override public boolean shouldFilter() { // 是否执行该过滤器,此处为true,说明需要过滤 return true; } @Override public int filterOrder() { // 优先级为0,数字越大,优先级越低 return 0; } @Override public String filterType() { // 前置过滤器 return "pre"; }}
Zuul请求的生命周期如图所示:
五、设置熔断
通常在服务无法提供服务的时候,需要执行熔断。zuul上实现熔断需要实现FallbackProvider的接口。实现接口中的两个方法:getRoute()用于指定应用在哪个服务上;fallbackResponse()进入熔断功能的执行逻辑。示例如下:
@Componentpublic class CustomZuulFallbackHandler implements FallbackProvider { private final Logger logger = LoggerFactory.getLogger(FallbackProvider.class); /** * 指定处理的service * * @return */ @Override public String getRoute() { return "*"; } public ClientHttpResponse fallbackResponse(String route) { return new ClientHttpResponse() { @Override public HttpStatus getStatusCode() throws IOException { return HttpStatus.OK; } @Override public int getRawStatusCode() throws IOException { return 200; } @Override public String getStatusText() throws IOException { return "OK"; } @Override public void close() { } @Override public InputStream getBody() throws IOException { return new ByteArrayInputStream((route+" is unavailable.").getBytes()); } @Override public HttpHeaders getHeaders() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); return headers; } }; } @Override public ClientHttpResponse fallbackResponse(String route, Throwable cause) { if (cause != null) { String reason = cause.getMessage(); logger.info("Excption {}",reason); } return fallbackResponse(route); }}
六、实战
6.1 pom文件
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <groupId>com.southgis.ibase.parent</groupId> <artifactId>parentWebService</artifactId> <version>2.0.1-SNAPSHOT</version> <relativePath>../../parent/parentWebService/pom.xml</relativePath> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>api-gateway</artifactId> <groupId>com.southgis.ibase.systemassistance</groupId> <version>2.0.1-SNAPSHOT</version> <packaging>war</packaging> <description>网关服务</description> <dependencies> <!--服务注册与发现--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <!--配置中心--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-client</artifactId> </dependency> <!--路由网关--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency> <!--cas 客户端--> <dependency> <groupId>org.jasig.cas.client</groupId> <artifactId>cas-client-core</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <finalName>apiGateway</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <mainClass>com.southgis.ibase.systemassistance.ApiGatewayCustomApplication</mainClass> </configuration> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build></project>
6.2 配置文件
bootstrap.properties
#服务名 对应配置文件中的{application}部分spring.application.name=apiGateway#对应前配置文件中的{profile}部分spring.cloud.config.profile=dev2#配置访问路径server.servlet.context-path=/eureka-server#注册中心eureka.client.serviceUrl.defaultZone=http://localhost:8080/eureka-server/eureka#为监控端点 /info和/health端点也加上类似的前缀management.server.servlet.context-path=/apiGatewayeureka.instance.statusPageUrlPath=${management.server.servlet.context-path}/actuator/infoeureka.instance.healthCheckUrlPath=${management.server.servlet.context-path}/actuator/health#通过服务连接配置中心#spring.cloud.config.discovery.enabled=true#spring.cloud.config.discovery.serviceId=config-serverspring.cloud.config.uri = http://localhost:8080/config-server#配置文件获取失败快速返回spring.cloud.config.failFast=true#日志配置#logging.config=classpath:logback-spring.xml#logging.path=D:/ibase/logs/holiday#logging.pattern.console=[%d{yyyy-MM-dd HH:mm:ss}] -- [%-5p]: [%c] -- %m%n#logging.pattern.file=[%d{yyyy-MM-dd HH:mm:ss}] -- [%-5p]: [%c] -- %m%n
apiGateway-dev2.properties
#访问端口server.port=8080#设置session超时时间为540分钟server.servlet.session.timeout=PT540M#zuul默认为所有服务开启默认的路由,为了服务安全,此处关闭zuul.ignored-services=*#代码字典服务路由zuul.routes.codedict.path=/codedict/**zuul.routes.codedict.service-id=codedict#是否转发后还带转发特征的字符zuul.routes.codedict.strip-prefix=false#行政区划服务路由zuul.routes.adminzone.path=/adminzone/**zuul.routes.adminzone.service-id=adminzonezuul.routes.adminzone.strip-prefix=false#是否开启路由重试zuul.retryable=true#对当前服务的重试次数ribbon.MaxAutoRetries=2#切换实例的重试次数ribbon.MaxAutoRetriesNextServer=0#请求处理的超时时间ribbon.ReadTimeout=6000#请求连接的超时时间ribbon.ConnectTimeout=6000#对所有操作请求都进行重试ribbon.OkToRetryOnAllOperations=true#将 hystrix 的超时时间设置成 5000 毫秒(hystrix超时时间小于ribbon连接超时时间,先走hystrix)hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000
6.3 过滤器配置
@Configurationpublic class ApiGatewayFilter extends ZuulFilter { @Override public String filterType() { return "pre"; } @Override public int filterOrder() { return 0; } @Override public boolean shouldFilter() { return true; } @Override public Object run() throws ZuulException { RequestContext context = RequestContext.getCurrentContext(); HttpServletRequest request = context.getRequest(); Principal principal = request.getUserPrincipal(); //获取用户的登录id String userId = principal.getName(); context.addZuulRequestHeader("X-AUTH-ID",userId); return null; }}
在这里我们将获取的登录用户id设置到了请求头中传递给内部服务,内部服务可以通过下面的代码进行获取:
String user = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getHeader("X-AUTH-ID");
6.4 熔断配置
@Componentpublic class CustomZuulFallbackHandler implements FallbackProvider { private final Logger logger = LoggerFactory.getLogger(FallbackProvider.class); /** * 指定处理的service * * @return */ @Override public String getRoute() { return "*"; } public ClientHttpResponse fallbackResponse(String route) { return new ClientHttpResponse() { @Override public HttpStatus getStatusCode() throws IOException { return HttpStatus.OK; } @Override public int getRawStatusCode() throws IOException { return 200; } @Override public String getStatusText() throws IOException { return "OK"; } @Override public void close() { } @Override public InputStream getBody() throws IOException { return new ByteArrayInputStream((route+" is unavailable.").getBytes()); } @Override public HttpHeaders getHeaders() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); return headers; } }; } @Override public ClientHttpResponse fallbackResponse(String route, Throwable cause) { if (cause != null) { String rea
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。