在正式实例之前,可以看一下之前对网关的介绍,学起来更轻松。
https://blog.csdn.net/wangyunzhao007/article/details/105770652
实例
在使用eureka是搭建好的框架,我们继续使用,搭建博客如下:
https://blog.csdn.net/wangyunzhao007/article/details/105776190
zuul的简单应用
zuul的四种路由
1.通过直接路由
新建立一个maven项目,其中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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.test</groupId>
<artifactId>zuul</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>zuul</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</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>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
引导类
@SpringBootApplication
@EnableZuulProxy //启动zuul组件
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
yml配置
server:
port: 10010 #服务端口
spring:
application:
name: api-gateway #指定服务名
zuul:
routes:
service-provider: # 这里是路由id,随意写
path: /service-provider/** # 这里是映射路径
url: http://127.0.0.1:8079 # 映射路径对应的实际url地址
我们这浏览器地址栏输入http://localhost:10010/service-provider/test/789
2.通过eureka中的服务id
首先我们加入eureka的依赖后,所有的依赖变成如下:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.test</groupId>
<artifactId>zuul</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>zuul</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</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>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
然后在引导类上加入eureka的启动注解
@SpringBootApplication
@EnableZuulProxy //启动zuul组件
@EnableEurekaClient //启动eureka
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
yml文件修改为
server:
port: 10010 #服务端口
spring:
application:
name: api-gateway #指定服务名
zuul:
routes:
service-provider: # 这里是路由id,随意写
path: /service-provider/** # 这里是映射路径
# url: http://127.0.0.1:8079 # 映射路径对应的实际url地址
serviceId: service-provider
eureka:
client:
service-url:
defaultZone: http://localhost:10086/eureka
然后继续通过网关调用接口,http://localhost:10010/service-provider/test/9877,结果正常。
3.取消path,和服务id,直接在service-provider后添加路由名称
只需要修改yml,配置如下
server:
port: 10010 #服务端口
spring:
application:
name: api-gateway #指定服务名
zuul:
routes:
service-provider: /service-provider/** # 这里是路由id,随意写,可以配置多个
service-consumer: /consumer/**
eureka:
client:
service-url:
defaultZone: http://localhost:10086/eureka
然后继续使用网关进行访问: http://localhost:10010/service-provider/test/9655,效果如下。
还可增加地址前缀,yml配置如下
server:
port: 10010 #服务端口
spring:
application:
name: api-gateway #指定服务名
zuul:
routes:
service-provider: /service-provider/** # 这里是路由id,随意写
service-consumer: /consumer/**
prefix: /api #地址前缀
eureka:
client:
service-url:
defaultZone: http://localhost:10086/eureka
效果如下
4.不用配置,默认就是服务id开头路径
zuul的过滤器
过滤器简介
Zuul作为网关的其中一个重要功能,就是实现请求的鉴权。而这个动作我们往往是通过Zuul提供的过滤器来实现的。
ZuulFilter是过滤器的顶级父类,实现过滤器基本就是继承顶级过滤器,然后重写方法。
在这里我们看一下其中定义的4个最重要的方法:
public abstract ZuulFilter implements IZuulFilter{
abstract public String filterType();
abstract public int filterOrder();
boolean shouldFilter();// 来自IZuulFilter
Object run() throws ZuulException;// IZuulFilter
}
-
shouldFilter
:返回一个Boolean
值,判断该过滤器是否需要执行。返回true执行,返回false不执行。 -
run
:过滤器的具体业务逻辑。 -
filterType
:返回字符串,代表过滤器的类型。包含以下4种:-
pre
:请求在被路由之前执行 -
route
:在路由请求时调用 -
post
:在route和errror过滤器之后调用 -
error
:处理请求时发生错误调用
-
-
filterOrder
:通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高。
下面是官网提供的一个请求生命周期图,清晰的表现了一个请求在各个过滤器的执行顺序。
有关于这张图的解释(一个请求在过滤器中的流程):
正常流程:
-
请求到达首先会经过pre类型过滤器,而后到达route类型,进行路由,请求就到达真正的服务提供者,执行请求,返回结果后,会到达post过滤器。而后返回响应。
异常流程:
-
整个过程中,pre或者route过滤器出现异常,都会直接进入error过滤器,在error处理完毕后,会将请求交给POST过滤器,最后返回给用户。
-
如果是error过滤器自己出现异常,最终也会进入POST过滤器,将最终结果返回给请求客户端。
-
如果是POST过滤器出现异常,会跳转到error过滤器,但是与pre和route不同的是,请求不会再到达POST过滤器了。
自定义过滤器
我们需要继承顶级过滤器,重写四个重要方法。
新建过滤器类。
类中的代码为
package com.test.zuul.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpStatus;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
public class TestFilter extends ZuulFilter {
/**
* 过滤器的类型:pre route post error
* @return
*/
@Override
public String filterType() {
return "pre";
}
/**
*执行顺序,返回值越小,优先级越高
* true:执行run方法
* @return
*/
@Override
public int filterOrder() {
return 10;
}
/**
* 是否执行该过滤器
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 编写过滤器的业务逻辑
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
//初始化context上下文对象 servlet spring
RequestContext context = RequestContext.getCurrentContext();
//获取request对象
HttpServletRequest request = context.getRequest();
//获取参数
String token = request.getParameter("token");
if (StringUtils.isBlank(token)){
// 拦截,不转发请求
context.setSendZuulResponse(false);
//响应状态码,401-身份为认证
context.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
context.setResponseBody("requst error!");
}
// 返回值为null,代表该过滤器什么都不做
return null;
}
}
在浏览器中输入 请求的地址:http://localhost:10010/api/service-provider/test/9655
由于我们在拦截器中验证是否存在token,明显我们没有带着token去发送请求,故而拦截器发生了作用,并且返回了我们自定义的新信息。效果如下: