源码地址:https://pan.baidu.com/s/1Hmvh1Bbss_Z1w1I7I1mwDw 提取码:e41h
在实际生产的项目中,很多项目并不是输入路径就直接调用服务的,通常在中间进行了一次转发,类似于 nginx 的反向代理。springcloud 就有集成了一个路由网关组件 Zuul。
Zuul 路由网关的主要用途是转发和过滤,转发请求,对一些请求进行过滤。
使用 Zuul 可以很轻松实现:
创建一个 zuul 服务
1. pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
<version>1.4.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.RELEASE</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>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
需要加入 zuul 依赖
2. application.properties
eureka.client.serviceUrl.defaultZone=http://localhost:7070/eureka/
server.port=7075
spring.application.name=zuul
zuul.routes.api-100.path=/api-serviceA/**
zuul.routes.api-100.service-id=serviceA
zuul.routes.xiao-c.path=/api-rest/**
zuul.routes.xiao-c.service-id=service-rest
###一行配置搞定,zuul-routes 后面直接接服务名,作用同上面两行,可并存
zuul.routes.service-rest=/xiao-rest/**
zuul.routes.api-a.path 表示在网关输入的路径 zuul.routes.api-a.service-id 表示要转发的目标,这里写的是服务名
path 和 service-id 构成一组
zuul.routes 后面的那个字段可以是任意数字及字母
根据上面的配置,地址 /api-rest/** 与 /xiao-rest/** 都将转发到 service-rest 服务
3. 启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableZuulProxy
public class ZuulApp {
public static void main(String[] args) {
SpringApplication.run(ZuulApp.class, args);
}
}
@EnableZuulProxy 启用路由
以上3步就实现了一个可以 转发请求 的服务工程了。
路由网关测试
启动注册中心,启动 serviceA1 服务、 service-rest 服务和 zuul 服务。
输入 localhost:7075/api-rest/getListRest
输入 localhost:7075/xiao-rest/getListRest
说明通过路由网关,请求确实转发到了 service-rest ,对同一个服务可以同时配置多个路由。
加入过滤功能
新建一个 MyFilter 类,继承 ZuulFilter
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
@Component
public class MyFilter extends ZuulFilter {
private static Logger log = LoggerFactory.getLogger(MyFilter.class);
// 过滤类型
@Override
public String filterType() {
return "pre";
}
// 过滤优先级
@Override
public int filterOrder() {
return 0;
}
// 是否过滤
public boolean shouldFilter() {
return true;
}
// 过滤逻辑
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
log.info(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
Object accessToken = request.getParameter("token");
if (accessToken != null) {
return null;
}
log.warn("token is empty");
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
try {
ctx.getResponse().getWriter().write("token is empty");
} catch (Exception e) {
}
return null;
}
}
使用@Component 把这个 Bean 注入到容器就可以生效了
String filterType()
- pre:可以在请求被路由之前调用
- routing: 路由请求时被调用
- post:在routing和error过滤器之后被调用
- error:处理请求时发生错误时被调用
int filterOrder();
数值越小优先级越高
boolean shouldFilter();
返回一个boolean值来判断该过滤器是否要执行
Object run();
过滤器的具体逻辑
zuul 过滤详解参考 https://www.jianshu.com/p/ff863d532767
加入过滤器功能后重启 zuul 服务
输入 localhost:7075/xiao-rest/getListRest 效果如下图
输入 localhost:7075/xiao-rest/getListRest?token=xiao123 效果如下图
本例的 MyFilter 的过滤逻辑需要判断 token 参数
博主经验尚浅,也暂无微服务相关项目经验,如果理解不到位甚至理解错误,希望评论区讨论,请多指教!