Zuul路由网关简介及基本使用
简介
请看下图,这里的API 路由网关服务 由Zuul实现,主要就是对外提供服务接口的时候,起到了请求的路由和过滤作用,也因此能够隐藏内部服务的接口细节,从来有利于保护系统的安全性;
路由配置
Zuul 路由配置
我们新建一个module microservice-zuul-3001
这里我们的zuul也注册到eureka服务里,端口3001;
我们修改下Hosts,专门为zuul搞个本地域名映射
pom依赖
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4 <modelVersion>4.0.0</modelVersion> 5 <parent> 6 <groupId>com.javaqi</groupId> 7 <artifactId>qimicroservice</artifactId> 8 <version>1.0-SNAPSHOT</version> 9 </parent> 10 <artifactId>microservice-zuul-3001</artifactId> 11 12 <properties> 13 <java.version>1.8</java.version> 14 </properties> 15 16 <dependencies> 17 <dependency> 18 <groupId>org.springframework.boot</groupId> 19 <artifactId>spring-boot-starter-web</artifactId> 20 </dependency> 21 <dependency> 22 <groupId>org.springframework.boot</groupId> 23 <artifactId>spring-boot-starter-test</artifactId> 24 <scope>test</scope> 25 </dependency> 26 <dependency> 27 <groupId>org.springframework.cloud</groupId> 28 <artifactId>spring-cloud-starter-eureka</artifactId> 29 </dependency> 30 31 <!-- actuator监控 --> 32 <dependency> 33 <groupId>org.springframework.boot</groupId> 34 <artifactId>spring-boot-starter-actuator</artifactId> 35 </dependency> 36 <!-- hystrix容错 --> 37 <dependency> 38 <groupId>org.springframework.cloud</groupId> 39 <artifactId>spring-cloud-starter-hystrix</artifactId> 40 </dependency> 41 <dependency> 42 <groupId>org.springframework.cloud</groupId> 43 <artifactId>spring-cloud-starter-config</artifactId> 44 </dependency> 45 <!--zuul网关--> 46 <dependency> 47 <groupId>org.springframework.cloud</groupId> 48 <artifactId>spring-cloud-starter-zuul</artifactId> 49 </dependency> 50 51 <!--ribbon相关依赖--> 52 <dependency> 53 <groupId>org.springframework.cloud</groupId> 54 <artifactId>spring-cloud-starter-eureka</artifactId> 55 </dependency> 56 <dependency> 57 <groupId>org.springframework.cloud</groupId> 58 <artifactId>spring-cloud-starter-ribbon</artifactId> 59 </dependency> 60 <dependency> 61 <groupId>org.springframework.cloud</groupId> 62 <artifactId>spring-cloud-starter-config</artifactId> 63 </dependency> 64 65 <!--引入Feign依赖--> 66 <dependency> 67 <groupId>org.springframework.cloud</groupId> 68 <artifactId>spring-cloud-starter-feign</artifactId> 69 </dependency> 70 </dependencies> 71 72 <build> 73 <plugins> 74 <plugin> 75 <groupId>org.springframework.boot</groupId> 76 <artifactId>spring-boot-maven-plugin</artifactId> 77 </plugin> 78 </plugins> 79 </build> 80 </project>
application.yml
1 server: 2 port: 3001 3 context-path: / 4 spring: 5 application: 6 name: microservice-zuul 7 eureka: 8 instance: 9 instance-id: microservice-zuul:3001 10 prefer-ip-address: true 11 client: 12 service-url: 13 defaultZone: http://eureka2001.javaqi.com:2001/eureka/,http://eureka2002.javaqi.com:2002/eureka/,http://eureka2003.javaqi.com:2003/eureka/ 14 info: 15 groupId: com.javaxl.testSpringcloud 16 artifactId: microservice-zuul-3001 17 version: 1.0-SNAPSHOT 18 userName: http://javaqi.com 19 phone: 123456 20 feign: 21 hystrix: 22 enabled: true 23 24 hystrix: 25 command: 26 default: 27 execution: 28 timeout: 29 enabled: true 30 isolation: 31 thread: 32 timeoutInMilliseconds: 15000 33 ribbon: 34 ReadTimeout: 6000 35 ConnectTimeout: 6000 36 MaxAutoRetries: 0 37 MaxAutoRetriesNextServer: 1 38 eureka: 39 enabled: true
主启动类:ZuulApplication_3001
加下@EnableZuulProxy注解
1 package com.javaqi.microservicezuul3001; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 6 import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; 7 import org.springframework.cloud.netflix.zuul.EnableZuulProxy; 8 9 @SpringBootApplication(exclude={DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class}) 10 @EnableZuulProxy 11 public class MicroserviceZuul3001Application { 12 13 public static void main(String[] args) { 14 SpringApplication.run(MicroserviceZuul3001Application.class, args); 15 } 16 17 }
我们测试下:
启动三个eureka 然后再启动下一个1006服务,以及 zuul网关服务;
我们直接请求:http://localhost:1006/student/list 能获取到数据;
我们用 http://zuul.javaqi.com:3001/microservice-student/student/list 域名+端口+服务名称+请求地址 也能请求到数据;
Zuul路由映射配置
上面是zuul的简单使用,从接口地址很轻易的就暴露了服务提供者的唯一标识名microservice-student;有安全风险,我们需要将其隐藏;
ignored-services的作用是将原来的服务提供者唯一标识名禁用;
Prefix的作用是给服务加前缀
yml文件中添加以下配置
1 zuul: 2 routes: 3 studentServer.serviceId: microservice-student 4 studentServer.path: /studentServer/** 5 ignored-services: "*" 6 prefix: /javaqi
配置完毕后可通过以下链接做测试
http://zuul.javaqi.com:3001/microservice-student/student/list
http://zuul.javaqi.com:3001/studentServer/student/list
http://zuul.javaqi.com:3001/javaqi/microservice-student/student/list
http://zuul.javaqi.com:3001/javaqi/studentServer/student/list
对应的配置会出现上面的错误页面,这是正常现象。
关于zuul使用后的容错处理
方案一(不推荐):
内部服务Hystrix与feign的整合失效,不能走快速回退的方法,雪崩现象再现
zuul的application.yml中配置
1 server: 2 port: 3001 3 context-path: / 4 spring: 5 application: 6 name: microservice-zuul 7 eureka: 8 instance: 9 instance-id: microservice-zuul:3001 10 prefer-ip-address: true 11 client: 12 service-url: 13 defaultZone: http://eureka2001.javaqi.com:2001/eureka/,http://eureka2002.javaqi.com:2002/eureka/,http://eureka2003.javaqi.com:2003/eureka/ 14 info: 15 groupId: com.javaqi.testSpringcloud 16 artifactId: microservice-zuul-3001 17 version: 1.0-SNAPSHOT 18 userName: http://javaqi.com 19 phone: 123456 20 21 zuul: 22 routes: 23 studentServer.serviceId: microservice-student 24 studentServer.path: /studentServer/** 25 ignored-services: "*" 26 prefix: /javaqi 27 host: 28 socket-timeout-millis: 60000 29 connect-timeout-millis: 60000 30 31 feign: 32 hystrix: 33 enabled: true 34 35 hystrix: 36 command: 37 default: 38 execution: 39 timeout: 40 enabled: true 41 isolation: 42 thread: 43 timeoutInMilliseconds: 15000 44 ribbon: 45 ReadTimeout: 6000 46 ConnectTimeout: 6000 47 MaxAutoRetries: 0 48 MaxAutoRetriesNextServer: 1 49 eureka: 50 enabled: true 51
以及pom
1 <dependencies> 2 <dependency> 3 <groupId>com.javaqi</groupId> 4 <artifactId>microservice-common</artifactId> 5 </dependency> 6 <dependency> 7 <groupId>org.springframework.boot</groupId> 8 <artifactId>spring-boot-starter-web</artifactId> 9 </dependency> 10 <dependency> 11 <groupId>org.springframework.boot</groupId> 12 <artifactId>spring-boot-starter-test</artifactId> 13 <scope>test</scope> 14 </dependency> 15 <dependency> 16 <groupId>org.springframework.cloud</groupId> 17 <artifactId>spring-cloud-starter-eureka</artifactId> 18 </dependency> 19 20 <!-- actuator监控 --> 21 <dependency> 22 <groupId>org.springframework.boot</groupId> 23 <artifactId>spring-boot-starter-actuator</artifactId> 24 </dependency> 25 <!-- hystrix容错 --> 26 <dependency> 27 <groupId>org.springframework.cloud</groupId> 28 <artifactId>spring-cloud-starter-hystrix</artifactId> 29 </dependency> 30 <dependency> 31 <groupId>org.springframework.cloud</groupId> 32 <artifactId>spring-cloud-starter-config</artifactId> 33 </dependency> 34 <!--zuul网关--> 35 <dependency> 36 <groupId>org.springframework.cloud</groupId> 37 <artifactId>spring-cloud-starter-zuul</artifactId> 38 </dependency> 39 40 <!--ribbon相关依赖--> 41 <dependency> 42 <groupId>org.springframework.cloud</groupId> 43 <artifactId>spring-cloud-starter-eureka</artifactId> 44 </dependency> 45 <dependency> 46 <groupId>org.springframework.cloud</groupId> 47 <artifactId>spring-cloud-starter-ribbon</artifactId> 48 </dependency> 49 <dependency> 50 <groupId>org.springframework.cloud</groupId> 51 <artifactId>spring-cloud-starter-config</artifactId> 52 </dependency> 53 54 <!--引入Feign依赖--> 55 <dependency> 56 <groupId>org.springframework.cloud</groupId> 57 <artifactId>spring-cloud-starter-feign</artifactId> 58 </dependency> 59 </dependencies>
方案二(推荐):
Zuul作为服务网关为了保证自己不被服务拖垮,本身已经集成了Hystrix对路由转发进行隔离。 为了方便开发人员对服务短路进行自定义处理,
1 package com.javaqi.microservicezuul3001.fallback; 2 3 import org.springframework.cloud.netflix.zuul.filters.route.ZuulFallbackProvider; 4 import org.springframework.http.HttpHeaders; 5 import org.springframework.http.HttpStatus; 6 import org.springframework.http.MediaType; 7 import org.springframework.http.client.ClientHttpResponse; 8 import org.springframework.stereotype.Component; 9 10 import java.io.ByteArrayInputStream; 11 import java.io.IOException; 12 import java.io.InputStream; 13 14 @Component 15 public class ZuulFallBack implements ZuulFallbackProvider { 16 17 @Override 18 public String getRoute() { 19 return "*"; 20 } 21 22 /** 23 * 在给zuul整合回退功能时,只要类实现ZuulFallbackProvider接口,并且注册bean即可。 24 * 25 * 不过需要注意的时,这个回退只有服务掉线或者超时的情况下才会触发(Camden.SR4版本测试是这样), 26 * 如果服务程序出现异常,此回退程序是不能处理的,异常会直接返回给调用者,比如页面。 27 * 28 * @return 29 */ 30 @Override 31 public ClientHttpResponse fallbackResponse() { 32 return new ClientHttpResponse() { 33 @Override 34 public HttpHeaders getHeaders() { 35 HttpHeaders headers = new HttpHeaders(); 36 headers.setContentType(MediaType.APPLICATION_JSON_UTF8);//application/json;charset=UTF-8 37 return headers; 38 } 39 40 @Override 41 public InputStream getBody() throws IOException { 42 String msg = "服务繁忙,请稍后....."; 43 //new ByteArrayInputStream("{"code":-1,"msg":"服务暂不可用"}".getBytes(StandardCharsets.UTF_8)) 44 return new ByteArrayInputStream(msg.getBytes()); 45 } 46 47 @Override 48 public String getStatusText() throws IOException { 49 return HttpStatus.BAD_REQUEST.getReasonPhrase();//400 50 } 51 52 @Override 53 public HttpStatus getStatusCode() throws IOException { 54 return HttpStatus.BAD_REQUEST; 55 } 56 57 @Override 58 public int getRawStatusCode() throws IOException { 59 return HttpStatus.BAD_REQUEST.value();//"Bad Request" 60 } 61 62 @Override 63 public void close() { 64 65 } 66 }; 67 } 68 }
Zuul请求过滤配置
比如我们登录某个系统 需要身份验证,用户名密码啥的;
我们请求服务,也可以来设置身份验证,也就是过滤非法请求;Zuul通过ZuulFilter过滤器实现;
一般具体实现的话 每次经过Zuul服务网关 我们都对带来的token进行有效性验证;
AccessFilter类:
1 package com.javaqi.microservicezuul3001.filter; 2 3 import com.netflix.zuul.ZuulFilter; 4 import com.netflix.zuul.context.RequestContext; 5 import com.netflix.zuul.exception.ZuulException; 6 import org.apache.log4j.Logger; 7 8 import javax.servlet.http.HttpServletRequest; 9 10 public class AccessFilter extends ZuulFilter { 11 12 Logger logger=Logger.getLogger(AccessFilter.class); 13 14 /** 15 * 判断该过滤器是否要被执行 16 */ 17 @Override 18 public boolean shouldFilter() { 19 return true; 20 } 21 22 /** 23 * 过滤器的具体执行逻辑 24 */ 25 @Override 26 public Object run() throws ZuulException { 27 RequestContext ctx = RequestContext.getCurrentContext(); 28 HttpServletRequest request = ctx.getRequest(); 29 String parameter = request.getParameter("accessToken"); 30 logger.info(request.getRequestURL().toString()+" 请求访问"); 31 if(parameter==null){ 32 logger.error("accessToken为空!"); 33 ctx.setSendZuulResponse(false); 34 ctx.setResponseStatusCode(401); 35 ctx.setResponseBody("{"result":"accessToken is empty!"}"); 36 return null; 37 } 38 // token判断逻辑 39 logger.info(request.getRequestURL().toString()+" 请求成功"); 40 return null; 41 } 42 43 /** 44 * 过滤器的类型 这里用pre,代表会再请求被路由之前执行 45 */ 46 @Override 47 public String filterType() { 48 return "pre"; 49 } 50 51 /** 52 * 过滤器的执行顺序 53 */ 54 @Override 55 public int filterOrder() { 56 return 0; 57 } 58 59 }
然后再开启下 Filter配置:
1 package com.javaqi.microservicezuul3001.config; 2 3 import com.javaqi.microservicezuul3001.filter.AccessFilter; 4 import com.javaqi.microservicezuul3001.filter.AccessFilter; 5 import org.springframework.context.annotation.Bean; 6 import org.springframework.context.annotation.Configuration; 7 8 @Configuration 9 public class ZuulConfig { 10 11 @Bean 12 public AccessFilter accessFilter(){ 13 return new AccessFilter(); 14 } 15 }
浏览器输入地址进行测试
http://zuul.javaqi.com:3001/javaqi/studentServer/student/list
http://zuul.javaqi.com:3001/javaqi/studentServer/student/list?accessToken=1
测试结果如下