Zuul
项目搭建参考https://blog.csdn.net/qq_40977118/article/details/104738485
1. 服务网关
- Zuul是分布式springcloud项目的流量入口,理论上所有进入到微服务系统的请求都要经过zuul来过滤和路由。
2. pom引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.spring.fisher</groupId>
<artifactId>micro-zuul</artifactId>
<version>1.0-SNAPSHOT</version>
<name>micro-zuul</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<spring-cloud.version>Hoxton.SR1</spring-cloud.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--eureka客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--zuul-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<!--配置中心-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>LATEST</version>
</dependency>
<!--健康检测-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
3. 创建启动类
package com.spring.fisher;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
@SpringBootApplication
//开启zuul路由功能
@EnableZuulProxy
public class MicroZuulApplication {
public static void main(String[] args) {
SpringApplication.run(MicroZuulApplication.class, args);
}
@Bean
//动态刷新配置中心的配置信息
@RefreshScope
//获取zuul开头的配置信息
@ConfigurationProperties("zuul")
@Primary
public ZuulProperties zuulProperties() {
return new ZuulProperties();
}
}
4. 配置文件
- 把web开头的请求,通过服务名称分配给micro-web的服务
- zuul内部包含ribbon和hystrix的功能,可以设置超时时间
spring.application.name=micro-zuul
server.port=7070
eureka.client.serviceUrl.defaultZone=http://root:root@localhost:8763/eureka/
# 使用路径方式匹配路由规则。
# 参数key结构: zuul.routes.customName.path=xxx
# 用于配置路径匹配规则。
# 其中customName自定义。通常使用要调用的服务名称,方便后期管理
# 可使用的通配符有: * ** ?
# ? 单个字符
# * 任意多个字符,不包含多级路径
# ** 任意多个字符,包含多级路径
zuul.routes.micro-web.path=/web/**
# 参数key结构: zuul.routes.customName.url=xxx
# url用于配置符合path的请求路径路由到的服务地址。
#zuul.routes.micro-order.url=http://localhost:8080/
# key结构 : zuul.routes.customName.serviceId=xxx
# serviceId用于配置符合path的请求路径路由到的服务名称。
zuul.routes.micro-web.serviceId=micro-web
# ignored service id pattern
# 配置不被zuul管理的服务列表。多个服务名称使用逗号','分隔。
# 配置的服务将不被zuul代理。
#zuul.ignored-services=eureka-application-service
# 此方式相当于给所有新发现的服务默认排除zuul网关访问方式,只有配置了路由网关的服务才可以通过zuul网关访问
# 通配方式配置排除列表。
zuul.ignored-services=*
# 通配方式配置排除网关代理路径。所有符合ignored-patterns的请求路径都不被zuul网关代理。
zuul.ignored-patterns=/**/local/**
# prefix URL pattern 前缀路由匹配
# 配置请求路径前缀,所有基于此前缀的请求都由zuul网关提供代理。
#zuul.prefix=/api
management.endpoints.web.exposure.include=*
# http://localhost:6060/actuator/hystrix.stream
#针对某个服务传输指定的headers信息 ,默认是过滤掉 Cookie,Set-Cookie,Authorization 这三个信息的
#这里置空就是不要过滤掉这三个
zuul.routes.micro-web.sensitive-headers=
#指定全局的headers传输,对所有路由的微服务
#zuul.sensitive-headers=Cookie,Set-Cookie,Authorization
#添加host头信息,标识最初的服务端请求地址
zuul.add-host-header=true
#默认添加 X-Forwarded-*头域
zuul.add-proxy-headers=true
zuul.routes.zuul-server.path=/local/**
zuul.routes.zuul-server.url=forward:/local
zuul.routes.blog.path=/blog/**
zuul.routes.blog.url=http://localhost:8003/
#全局关闭重试
zuul.retryable=false
#关闭该服务的重试
zuul.routes.micro-web.retryable=false
ribbon.ConnectTimeout=5000
ribbon.ReadTimeout=10000
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=100000
#如果没有从配置中心获取配置,可以设置为false
#否则会提示Could not locate PropertySource: I/O error on GET request for "http://localhost:8888/micro-zuul/default": Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect
#但是不影响程序正常运行
spring.cloud.config.enabled=false
5. 依次启动所有服务
6. 获取路由规则
- http://localhost:7070/actuator/routes
7. 打开hystrix监控
- http://localhost:9990/hystrix
- http://localhost:7070/actuator/hystrix.stream
8. 发起请求
- http://localhost:7070/web/queryUser
- 连续请求结果,,最终会调用到micro-web服务的接口
9. 使用配置中心
# 使用路径方式匹配路由规则。
# 参数key结构: zuul.routes.customName.path=xxx
# 用于配置路径匹配规则。
# 其中customName自定义。通常使用要调用的服务名称,方便后期管理
# 可使用的通配符有: * ** ?
# ? 单个字符
# * 任意多个字符,不包含多级路径
# ** 任意多个字符,包含多级路径
zuul.routes.micro-web.path=/web/**
# 参数key结构: zuul.routes.customName.url=xxx
# url用于配置符合path的请求路径路由到的服务地址。
#zuul.routes.micro-order.url=http://localhost:8080/
# key结构 : zuul.routes.customName.serviceId=xxx
# serviceId用于配置符合path的请求路径路由到的服务名称。
zuul.routes.micro-web.serviceId=micro-web
#zuul.routes.micro-web1.path=/web/path/**
#zuul.routes.micro-web1.serviceId=micro-web-no
# ignored service id pattern
# 配置不被zuul管理的服务列表。多个服务名称使用逗号','分隔。
# 配置的服务将不被zuul代理。
#zuul.ignored-services=eureka-application-service
# 此方式相当于给所有新发现的服务默认排除zuul网关访问方式,只有配置了路由网关的服务才可以通过zuul网关访问
# 通配方式配置排除列表。
zuul.ignored-services=*
# 通配方式配置排除网关代理路径。所有符合ignored-patterns的请求路径都不被zuul网关代理。
zuul.ignored-patterns=/**/local/**
# prefix URL pattern 前缀路由匹配
# 配置请求路径前缀,所有基于此前缀的请求都由zuul网关提供代理。
#zuul.prefix=/api
management.endpoints.web.exposure.include=*
# http://localhost:6060/actuator/hystrix.stream
#针对某个服务传输指定的headers信息 ,默认是过滤掉 Cookie,Set-Cookie,Authorization 这三个信息的
#这里置空就是不要过滤掉这三个
zuul.routes.micro-web.sensitive-headers=
#指定全局的headers传输,对所有路由的微服务
#zuul.sensitive-headers=Cookie,Set-Cookie,Authorization
#添加host头信息,标识最初的服务端请求地址
zuul.add-host-header=true
#默认添加 X-Forwarded-*头域
zuul.add-proxy-headers=true
zuul.routes.zuul-server.path=/local/**
zuul.routes.zuul-server.url=forward:/local
zuul.routes.blog.path=/blog/**
zuul.routes.blog.url=http://localhost:8003/
#全局关闭重试
zuul.retryable=false
#关闭该服务的重试
zuul.routes.micro-web.retryable=false
ribbon.ConnectTimeout=5000
ribbon.ReadTimeout=10000
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=100000
spring.application.name=api-gateway
server.port=7070
eureka.client.serviceUrl.defaultZone=http://root:root@localhost:8763/eureka/
spring.cloud.config.profile=dev
spring.cloud.config.label=master
#这种配置是configserver还单机情况,直接连接这个单机服务就行
#spring.cloud.config.uri=http://localhost:8085/
#configserver高可用配置
#开启configserver服务发现功能
spring.cloud.config.discovery.enabled=true
#服务发现的服务名称
spring.cloud.config.discovery.service-id=config-server
#如果连接不上获取配置有问题,快速响应失败
spring.cloud.config.fail-fast=true
#默认重试的间隔时间,默认1000ms
spring.cloud.config.retry.multiplier=1000
#下一间隔时间的乘数,默认是1.1
#spring.cloud.config.retry.initial-interval=1.1
#最大间隔时间,最大2000ms
spring.cloud.config.retry.max-interval=2000
#最大重试次数,默认6次
spring.cloud.config.retry.max-attempts=6
ribbon.ConnectTimeout=3000
ribbon.ReadTimeout=3000
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000
#spring.rabbitmq.host=192.168.67.139
#spring.rabbitmq.port=5672
#spring.rabbitmq.username=admin
#spring.rabbitmq.password=admin
management.endpoints.web.exposure.include=*
10. 重启服务
- 再次请求
11. 过滤器
Zuul大部分功能都是通过过滤器来实现的,Zuul定义了4种标准的过滤器类型,这些过滤器类型对应于请求的典型生命周期。
- pre: 这种过滤器在请求被路由之前调用。可利用这种过滤器实现身份验证、在集群中选择请求的微服务,记录调试信息等。
- routing: 这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用apache httpclient或netflix ribbon请求微服务。
- post: 这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的http header、收集统计信息和指标、将响应从微服务发送给客户端等。
- error: 在其他阶段发送错误时执行该过滤器。
1、PreFilter
package com.spring.fisher.filter;
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;
@Slf4j
@Component
public class PreFilter extends ZuulFilter {
@Override
public String filterType() {
//设置过滤器类型
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
//排序,数字越小,越优先执行
return 0;
}
@Override
public boolean shouldFilter() {
return RequestContext.getCurrentContext().sendZuulResponse();
}
@Override
public Object run() throws ZuulException {
//获取上下文
RequestContext ctx = RequestContext.getCurrentContext();
//获取Request
HttpServletRequest request = ctx.getRequest();
//获取请求参数accessToken
String accessToken = request.getParameter("accessToken");
//使用String工具类
if (StringUtils.isBlank(accessToken)) {
log.warn("accessToken is empty");
//设置为false不进行路由
ctx.setSendZuulResponse(false); //进行拦截
ctx.setResponseStatusCode(401);
try {
ctx.getResponse().getWriter().write("accessToken is empty");
} catch (Exception e) {
}
return null;
}
log.info("zuul pre filter-->" + request.getRequestURL() + "-->" + request.getMethod());
log.info("access is ok");
return null;
}
}
- http://localhost:7070/web/queryUser?accessToken=ok
- http://localhost:7070/web/queryUser
- 通过RequestContext.getCurrentContext().sendZuulResponse()获取sendZuulResponse的值,true则路由成功,false则不路由
- 通过ctx.setSendZuulResponse(false)方法,设置sendZuulResponse的值,可以靠这个值做权限校验