Zuul是所有设备和网站请求Netflix流应用程序后端的前门。作为一个边缘服务应用程序,Zuul旨在实现动态路由,监控,弹性和安全性。它还可以恰当的将请求路由到多个Amazon弹性集群中。
大量不同的Netflix API流量有时会导致迅速而无预警地出现问题。我们需要一个能够迅速改变行为的系统,以应对这些情况。
Zuul使用一系列不同类型的过滤器,使我们能够快速灵活地将这些功能应用于我们的边缘服务。这些过滤器可帮助我们执行以下功能:
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-eurekaartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-zuulartifactId>
dependency>
dependencies>
server:
port: 9999
spring:
application:
name: spring-cloud-zuul-gateway #为这个服务取名,非常重要!!!!!
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: zuul.com
prefer-ip-address: true
127.0.0.0 zuul.com
@SpringBootApplication
@EnableZuulProxy
public class SpringCloudZuulApplication9999 {
public static void main(String[] args) {
SpringApplication.run(SpringCloudZuulApplication9999.class, args);
}
}
server:
port: 9999
spring:
application:
name: spring-cloud-zuul-gateway #为这个服务取名,非常重要!!!!!
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: zuul.com
prefer-ip-address: true
zuul:
ignored-services: spring-cloud-provider #禁止通过微服务名访问,可以使用通配符*,需要加“\”转义
prefix: /mysevice #访问前缀,如果没有该配置,则访问路径不能以/zuul/开头
routes:
spring-cloud-provider: /myzuul/** #routes参数格式为Map,前者是key 为被代理服务名-spring-cloud-provider,后者是value为代理路径-/myzuul/** ;可以配置多个服务代理
#spring-cloud-provider1: /myzuul1/**
重行启动zuul服务,访问:http://zuul.com:9999/mysevice/myzuul/hello/jack
证明:只能通过http://[网关服务ip]:[网关服务端口]/[前缀][自己设置的路径]/[路径] 进行访问,不加前缀或者通过服务名访问都失败。
//使该类成为配置类,注入spring容器
@Configuration
public class MyZuulFilter extends ZuulFilter {
/**
* pre:在请求路由之前执行过滤。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
* route:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netfilx Ribbon请求微服务。
* post:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
* error:在其他阶段发生错误时执行该过滤器。
* 除了默认的过滤器类型,Zuul还允许我们创建自定义的过滤器类型。例如,我们可以定制一种STATIC类型的过滤器,直接在Zuul中生成响应,而不将请求转发到后端的微服务。
* to classify a filter by type. Standard types in Zuul are "pre" for pre-routing filtering,
* "route" for routing to an origin, "post" for post-routing filters, "error" for error handling.
* We also support a "static" type for static responses see StaticResponseFilter.
* Any filterType made be created or added and run by calling FilterProcessor.runFilters(type)
*
* @return A String representing that type
*/
@Override
public String filterType() {
return "pre";
}
/**
* 必须定义过滤器顺序,如果该过滤器的优先级不是很重要,过滤器顺序命令可以相同,过滤器命令不需要是连续的。
* 命令从0,1,2...优先级依次降低
* filterOrder() must also be defined for a filter. Filters may have the same filterOrder if precedence is not
* important for a filter. filterOrders do not need to be sequential.
* @return the int order of a filter
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 返回true run()方法将要执行,false将不执行,可以作为run() 方法执行开关。
* a "true" return from this method means that the run() method should be invoked
* @return true if the run() method should be invoked. false will not invoke the run() method
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 可以自己编写任意的业务逻辑
* if shouldFilter() is true, this method will be invoked. this method is the core method of a ZuulFilter
* @return Some arbitrary artifact may be returned. Current implementation ignores it.
*/
@Override
public Object run() {
System.out.println("shouldFilter() is true");
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
String requestURL = request.getRequestURL().toString();
int index = requestURL.lastIndexOf('/')+1;
String username = requestURL.substring(index);
//判定长度小于三为非法用户名
if (username.length() >2 ) {
return true;
}else{
throw new RuntimeException("非法用户名,请检查!");
}
}
}
Zuul中默认实现了DebugFilter、StaticResponseFilter等过滤器,具体信息可以看源码,可以以以下方式禁用某种过滤器
zuul:
FormBodyWrapperFilter:
pre:
disable: true
改写feign调用接口。
@FeignClient(name= "spring-cloud-zuul-gateway", fallback = HelloRemoteFallback.class)
public interface HelloRemote {
String ZUUL_URL_PREFIX = "/mysevice/myzuul";
@RequestMapping(value = ZUUL_URL_PREFIX+"/hello/{name}")
String hello(@RequestParam(value = "name") String name);
}
Zuul 是一个代理服务,如果被代理的服务突然宕机(如停掉provider 8001服务),那么zuul将会报错。但是consumer hystrix zuul服务已经有Feign降级服务,所以该服务不会报错,所有只有zuul报错,因此应该配置zuul的降级服务。
//注入容器
@Component
public class MyZuulFallbackProvider implements ZuulFallbackProvider {
/**
* 必须设置好处理的失败的服务路由
* @return
*/
@Override
public String getRoute() {
return "spring-cloud-provider";
}
@Override
public ClientHttpResponse fallbackResponse() {
return new ClientHttpResponse() {
/**
* 服务调用失败后返回
* @return
* @throws IOException
*/
@Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream("被代理服务故障,此结果由Zuul Gateway静态提供!".getBytes());
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders() ;
headers.set("Content-Type", "text/html; charset=UTF-8");
return headers;
}
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.BAD_REQUEST;
}
@Override
public int getRawStatusCode() throws IOException {
return HttpStatus.BAD_REQUEST.value();
}
@Override
public String getStatusText() throws IOException {
return HttpStatus.BAD_REQUEST.getReasonPhrase();
}
@Override
public void close() {
}};
}
}