Zuul网关
API网关
统一管理API的一个网络关口、通道,是整个微服务平台所有请求的唯一入口,所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有的非业务功能。有网关 | 没有网关 |
---|---|
有了网关后, 请求必须得要先经过网关, 确定这个请求是否合法,如果合法, zuul会对其做出判断 , 转发到指定的微服务,也会自动帮助做负责均衡 | 没有网关的时候, 用户可以随意访问一台微服务 |
Zuul概述
Zuul是Netflix出品的一个基于JVM路由和服务端的负载均衡器(网关);Zuul包含了对请求的路由和过滤两个最主要的功能:
1、路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础;
2、过滤器功能则负责对请求的处理过程进行干预,是实现请求校验、服务聚合等功能的基础;
Zuul也作为一个客户端注册进Eureka:
将Zuul自身注册为Eureka服务治理下的应用,同时从Eureka中获得其他微服务的消息,也即以后的访问微服务都是通过Zuul跳转后获得。
Zuul使用
在工程当中创建一个网关微服务1.导入zuul相关依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
2.创建启动类,在启动类上添加@EnableZuulProxy
3.创建配置文件
server:
port: 8003
eureka:
client:
serviceUrl:
#eureka服务端提供的注册地址 参考服务端配置的这个路径
defaultZone: http://eureka:3000/eureka,http://eureka1:3001/eureka,http://eureka2:3000/eureka2
instance:
instance-id: zull-0 #此实例注册到eureka服务端的唯一的实例ID
prefer-ip-address: true #是否显示IP地址
#eureka客户需要多长时间发送心跳给eureka服务器,表明它仍然活着,默认为30 秒 (与下面配置的单位都是秒)
leaseRenewalIntervalInSeconds: 1
#Eureka服务器在接收到实例的最后一次发出的心跳后,需要等待多久才可以将此实例删除,默认为90秒
leaseExpirationDurationInSeconds: 3
spring:
application:
name: client-zuul #此实例注册到eureka服务端的name
4.启动工程后,访问Eureka
5.启动一个goods(服务方,被调用的)工程
6.可以直接使用网关来调用goods(服务方,被调用的)工程当中的api:http://localhost:网关端口号/服务名称/api
zuul配置路由
在zuul的配置文件当中添加如下配置:
配置完成后,再访问地址:
http://localhost:8003/goods/getGoods.
禁用通过微服务的名称直接调用do:
再使用http://localhost:8003/provide-goods/getGoods.do调用就会失败
prefix:
访问时:http://localhost:8003/api/goods/getGoods.do
strip-prefix:
过滤器
过滤器(filter)是zuul的核心组件 zuul大部分功能都是通过过滤器来实现的
PRE | ROUTING | POST | ERROR |
---|---|---|---|
这种过滤器在请求被路由之前调用。 | 这种过滤器将请求路由到微服务。 | 这种过滤器在路由到微服务以后执行。 | 在其他阶段发生错误时执行该过滤器。 |
可利用这种过滤器实现身份验证、在 集群中选择请求的微服务、记录调试信息等。 | 这种过滤器用于构建发送给微服 务的请求,并使用 Apache HttpCIient或 Netfilx Ribbon请求微服务 | 这种过滤器可用来为响应添加标准 的 HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等 |
package com.fmjava.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
public class zullFilter extends ZuulFilter {
/**
* 返回过滤器的类型
*
* @return
*/
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;//前置过滤器
}
/**
* 返回指定过滤器的执行顺序
* <p>
* 越小越靠前
*
* @return
*/
@Override
public int filterOrder() {
//+1 在此过滤器之后执行
return FilterConstants.PRE_DECORATION_FILTER_ORDER+1;
}
/**
* 判断该过滤器是否要执行,true表示执行,false表示不执行
*
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 过滤器的具体逻辑
*
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String remoteAddr = request.getRemoteAddr();
System.out.println("访问者IP:"+remoteAddr+"访问地址:"+request.getRequestURI());
//可以通过strip-prefix: true/false确定是否要移除前缀
System.out.println("路由后的地址:"+ctx.get(FilterConstants.REQUEST_URI_KEY));
return null;
}
}
zuul容错与回退
zuul默认是整合了hystrix和ribbon的, 提供降级回退,当服务访问不通的时候,会调用自己提供的方法,是服务级别的实现步骤:
1.编写一个类,实现FallbackProvider
完整代码
@Component
public class ZuulFallBackProvider implements FallbackProvider {
//制定为哪个微服务提供回退(这里写微服务名 写*代表所有微服务)
@Override
public String getRoute() {
return "*";
}
//此方法需要返回一个ClientHttpResponse对象
// ClientHttpResponse是一个接口,具体的回退逻辑要实现此接口
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
//这里可以判断根据不同的异常来做不同的处理, 也可以不判断
//完了之后调用response方法并根据异常类型传入HttpStatus
if (cause instanceof HystrixTimeoutException) {
return response(HttpStatus.GATEWAY_TIMEOUT);
} else {
return response(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
private ClientHttpResponse response(final HttpStatus status) {
//这里返回一个ClientHttpResponse对象 并实现其中的方法,关于回退逻辑的详细,便在下面的方法中
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
//返回一个HttpStatus对象 这个对象是个枚举对象, 里面包含了一个status code 和reasonPhrase信息
return status;
}
@Override
public int getRawStatusCode() throws IOException {
//返回status的code 比如 404,500等
return status.value();
}
@Override
public String getStatusText() throws IOException {
//返回一个HttpStatus对象的reasonPhrase信息
return status.getReasonPhrase();
}
@Override
public void close() {
//close的时候调用的方法, 讲白了就是当降级信息全部响应完了之后调用的方法
System.out.println("close调用");
}
@Override
public InputStream getBody() throws IOException {
//把降级信息响应回前端
return new ByteArrayInputStream("系统繁忙,请稍后再试".getBytes());
}
@Override
public HttpHeaders getHeaders() {
//需要对响应报头设置的话可以在此设置
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
};
}
}
zuul集群
创建两个zuul服务代理服务
zuul服务1
zuul服务2