目录
一站式微服务架构SpringCloud-Netflix网关路由Zuul
项目中使用Zuul
创建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>
配置文件
server.port=90
spring.application.name=springcloud-zuul
#每2秒向服务端发送一次心跳,证明自己存活
eureka.instance.lease-renewal-interval-in-seconds=2
#告诉服务端,10秒之内没有发送心跳,就代表故障了
eureka.instance.lease-expiration-duration-in-seconds=10
#以IP作为链接
eureka.instance.prefer-ip-address=true
#实例名称
eureka.instance.instance-id=springcloud-zuul
#Eureka链接地址
eureka.client.service-url.defaultZone=http://47.110.157.82:8761/eureka,http://47.110.157.82:8762/eureka,http://47.110.157.82:8763/eureka
#设置zuul超时时间
zuul.host.connect-timeout-millis=5000
启动类添加@EnableZuulProxy
@EnableZuulProxy
@SpringBootApplication
public class SpringcloudDomeZuulApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudDomeZuulApplication.class, args);
}
}
测试:
通过Eureka的spring.application.name访问项目
自定义路由规则
配置文件中添加
#路由规则,producer是自己随便定义的
zuul.routes.producer.service-id=springcloud-producer
#?:匹配多个字符。*:匹配单层路径。 **:匹配:多层路径,/producer/**自己随便定义
zuul.routes.producer.path=/producer/**
测试:
将springcloud-producer替换成producer
禁用服务名访问项目和添加项目前缀
#忽略服务,禁止使用该服务名访问
#zuul.ignored-services=springcloud-producer
#忽略所有服务
zuul.ignored-services=*
#路径中存在save不能访问
zuul.ignored-patterns=/**/save/**
#添加前缀
zuul.prefix=/api
测试:
服务名无法访问
过滤器
自定义过滤器
@Component
public class MyFilter extends ZuulFilter {
/**
* 过滤器类型
* ERROR_TYPE = "error"; 过滤出错
* POST_TYPE = "post"; 过滤后
* PRE_TYPE = "pre"; 过滤前
* ROUTE_TYPE = "route"; 过滤时
* @return
*/
@Override
public String filterType() {
return FilterConstants.ROUTE_TYPE;
}
/**
* 过滤器优先级
* DEBUG_FILTER_ORDER = 1;
* FORM_BODY_WRAPPER_FILTER_ORDER = -1;
* PRE_DECORATION_FILTER_ORDER = 5;
* RIBBON_ROUTING_FILTER_ORDER = 10;
* SEND_ERROR_FILTER_ORDER = 0;
* SEND_FORWARD_FILTER_ORDER = 500;
* SEND_RESPONSE_FILTER_ORDER = 1000;
* SIMPLE_HOST_ROUTING_FILTER_ORDER = 100;
* SERVLET_30_WRAPPER_FILTER_ORDER = -2;
* SERVLET_DETECTION_FILTER_ORDER = -3;
* @return
*/
@Override
public int filterOrder() {
return FilterConstants.SEND_ERROR_FILTER_ORDER;
}
/**
* 是否开启过滤器
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 执行方法
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
HttpServletRequest request = RequestContext.getCurrentContext().getRequest();
String serverName = request.getServerName();
System.out.println("访问地址"+serverName+request.getRequestURI());
return null; //返回值无意义
}
}
测试
访问路由URL:http://localhost:90/api/producer/get
禁用过滤器
配置文件添加
#禁用过滤器。Myfilter过滤器类,route过滤器类型
zuul.Myfilter.route.disable=true
网关异常处理
关闭zuul自带异常处理
zuul.SendErrorFilter.error.disable=true
自定义异常处理类
@Component
public class ErrorFilter extends ZuulFilter {
@Override
public String filterType() {
return FilterConstants.ERROR_TYPE;
}
@Override
public int filterOrder() {
return 1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
try {
RequestContext currentContext = RequestContext.getCurrentContext();
ZuulException exception=(ZuulException) currentContext.getThrowable();
System.out.println("进入系统异常拦截"+exception.getMessage());
HttpServletResponse response = currentContext.getResponse();
response.setContentType("application/json; charset=utf8");
response.setStatus(exception.nStatusCode);
PrintWriter writer=null;
try{
writer=response.getWriter();
writer.print("{code:"+exception.nStatusCode+",message:\""+exception.getMessage()+"\"}");
}catch (IOException e){
e.printStackTrace();
}finally {
if(writer!=null){
writer.close();
}
}
}catch (Exception e){
ReflectionUtils.rethrowRuntimeException(e);
}
return null;
}
}
在自定义过滤器MyFilter中制造异常
/**
* 执行方法
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
HttpServletRequest request = RequestContext.getCurrentContext().getRequest();
String serverName = request.getServerName();
System.out.println("访问地址"+serverName+request.getRequestURI());
int a=10/0; //制造异常
return null; //返回值无意义
}
测试
zuul的熔断降级
创建zuul的降级类
@Component
public class ZuulFallBack implements FallbackProvider {
/**
* 配置需要降级的路由规则
* @return
*/
@Override
public String getRoute() {
return "*";
}
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return new ClientHttpResponse() {
/**
* 响应头
* @return
*/
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "text/html;charset=UTF-8");
return headers;
}
/**
* 响应体
* @return
* @throws IOException
*/
@Override
public InputStream getBody() throws IOException {
// 当出现服务调用错误之后返回的内容
// 服务端死掉,会自动找zuul的失败回退服务降级
return new ByteArrayInputStream("系统正在维护,请稍后再试!".getBytes());
}
/**
* 状态码
* @return
* @throws IOException
*/
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.BAD_REQUEST;
}
/**
* 状态码值
* @return
* @throws IOException
*/
@Override
public int getRawStatusCode() throws IOException {
return HttpStatus.BAD_REQUEST.value();
}
/**
* 状态码值文本
* @return
* @throws IOException
*/
@Override
public String getStatusText() throws IOException {
return HttpStatus.BAD_REQUEST.getReasonPhrase();
}
@Override
public void close() {
// TODO Auto-generated method stub
}
};
}
}
测试:
关闭zuul中的服务,然后通过zuul来访问服务