Zuul
API 网关
- 微服务系统统一的调用入口
- 统一的权限校验
- 集成ribbon
- 集成hystrix
zuul API 网关,为微服务应用提供统一的对外访问接口。
zuul 还提供过滤器,对所有微服务提供统一的请求校验。
统一的调用入口
-
zuul 依赖、eureka client依赖、sp01
-
yml
# 配置调用转发规则
# 下面是 zuul 默认的转发规则
# 如果不手动配置,zuul可以根据注册表的注册信息进行自动配置
zuul:
routes:
item-service: /item-service/**
user-service: /user-service/**
order-service: /order-service/**
- 启动类注解: @EnableZuulProxy
zuul 请求过滤
统一权限校验
通过 zuul 过滤器,可以判断用户是否有权限访问后台服务,如果没有权限可以阻止用户继续访问
判断用户是否登录,登录猜允许访问商品服务
http://localhost:3001/item-service/u45y45435 没有登录不允许访问
http://localhost:3001/item-service/u45y45435?token=y45343t4 有token认为登录过,允许访问
添加过滤器代码
1.继承ZuulProxy
2.添加@Component注解
zuul会对过滤器进行自动配置
package cn.tedu.sp11.filter;
import cn.tedu.sp01.util.JsonResult;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
@Slf4j
public class AccessFilter extends ZuulFilter {
//设置过滤器的类型:pre,routing,post,error
@Override
public String filterType() {
//设置成前置过滤器
return FilterConstants.PRE_TYPE;
}
//设置过滤器的顺序号
@Override
public int filterOrder() {
//默认有5个过滤器了,把它放到第6个
return 6;
}
/*
对当前请求进行判断
针对当前请求,是否要执行过滤代码
*/
@Override
public boolean shouldFilter() {
//如果调用item-service,执行过滤代码判断权限
//否则不执行过滤代码
//获取调用的服务id
RequestContext ctx=RequestContext.getCurrentContext();
String serviceId=(String)ctx.get(FilterConstants.SERVICE_ID_KEY);
//判断是不是item-service
return "item-service".equals(serviceId);
}
//过滤代码
@Override
public Object run() throws ZuulException {
//获取request对象
RequestContext ctx=RequestContext.getCurrentContext();
HttpServletRequest request=ctx.getRequest();
//接收token参数
String token=request.getParameter("token");
//如果没有收到token参数,认为用户没有登录,组织继续调用
if(StringUtils.isBlank(token)){
//阻止继续嗲用
ctx.setSendZuulResponse(false);
//从网关直接返回,设置向客户端发送的响应
ctx.addZuulResponseHeader("Content-type", "application/json");
ctx.setResponseBody(JsonResult.err().msg("not login").toString());
}
return null; //在当前zull版本中,这个返回值没有任何作用
}
}
重启服务器测试:
未提交token时:
提交token时:
zuul 集成 ribbon
默认启用了 ribbon 的负载均衡
默认不启用重试,zuul不推荐启用重试
启用重试:
- spring-retry 依赖
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
- yml
zuul.retryable=true
-
重试参数
有默认参数,可以根据需要进行调整
zuul 集成 hystrix
0配置,已经启用了hystrix
添加降级代码
- 实现 FallbackProvider 接口,在子类中实现降级代码
- @Component
zuul的自动配置,会自动配置降级类
Demo:
package cn.tedu.sp11.fallback;
import cn.tedu.sp01.util.JsonResult;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import javax.xml.ws.spi.http.HttpHandler;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
@Component
public class ItemFB implements FallbackProvider {
/*
返回service—id
针对那个服务进行降级
*/
/**
* 返回:
* "*" -针对所有服务进行降级
* null -针对所有服务进行降级
* @return
*/
@Override
public String getRoute() {
return "item-service";
}
/**
* 设置向客户端返回的降级响应
* @param route
* @param cause
* @return
*/
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
return HttpStatus.OK.value();
}
@Override
public String getStatusText() throws IOException {
return HttpStatus.OK.getReasonPhrase();
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
//JsonResult - {code:200,msg:"调用后台商品服务失败",data:null}
String json=JsonResult.ok().msg("调用后代服务商品失败").toString();
return new ByteArrayInputStream(json.getBytes("UTF-8"));
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders header=new HttpHeaders();
header.add("Content-Type", "application/json;charset=UTF-8");
return header;
}
};
}
}
Zuul 和 Feign场景
- 都可以调用后台服务
- 都可以集成 ribbon
- 都可集成 hystrix
zuul
-
部署在所有微服务项目之前
-
网关一般是一个独立的服务,与业务无关
-
不推荐启用重试
会造成后台服务压力翻倍
重试尽量不部署在最前面,越往后越好
feign
-
部署在微服务内部,服务和服务之间调用
-
不推荐启用 hystrix
一般在最前面进行降级和熔断,类似于电箱断路器,只在入户位置部署,
不在微服务内部部署hystrix,否则会引起混乱