1、新建一个Module,然后倒入下列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.chengxi</groupId>
<artifactId>zuul-test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>zuul-test</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.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>
<spring-cloud.version>Finchley.RC1</spring-cloud.version>
<jjwt.version>0.7.0</jjwt.version>
<joda-time.version>2.9.6</joda-time.version>
</properties>
<dependencies>
<!--导入服务网关zuul-->
<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>
</dependency>
<!--导入eureka客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--导入重试机制的坐标-->
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<!--引入Hystrix依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--导入jwt相关依赖-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jjwt.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/joda-time/joda-time -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>${joda-time.version}</version>
</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>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
2、启动类上加注解@EnableZuulProxy,这个注解整合了@EnableDiscoveryClient注解,所以不需要再加Eureka客户端的相关注解了
package com.example.lqzuul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableZuulProxy
public class LqZuulApplication {
public static void main(String[] args) {
SpringApplication.run(LqZuulApplication.class, args);
}
}
3、添加配置文件
简单使用网关的话,只需配置,端口port,服务名spring.application.name.路由规则即可
server:
port: 1085 # 端口号
spring:
application:
name: zuul-service # 网关服务名称
zuul:
prefix: /api # 访问网关路径的前缀(在映射路径的前面,一般用于区别开发的版本)
routes:
producer-service:
path: /hello/**
service-id: producer-service
# 因为zuul是整合ribbon和hystrix的另一个客户端,所以我们需要自己导入spring-retry坐标,并且开启服务
retryable: true
# 配置zuul的连接时间,一般不需要配置
# host:
# max-per-route-connections:
# socket-timeout-millis:
# connect-timeout-millis:
# ignored-services: microservice-comsumer-movie-ribbon-withhystrix # 这是表示某一个服务不允许代理,上面配置的是需要代理的
eureka:
client:
registry-fetch-interval-seconds: 5 # 获取注册列表的周期
service-url:
# eureka注册中心地址
defaultZone: http://127.0.0.1:1111/eureka
instance:
prefer-ip-address: true # 返回ip地址而不是hostname
ip-address: 127.0.0.1 # 本机地址
ribbon:
ConnectTimeout: 250 # 连接超时时间(ms),默认值为250ms
ReadTimeout: 2000 # 通信超时时间(ms),默认值为2000ms
OkToRetryOnAllOperations: true # 是否对所有操作都进行重试
MaxAutoRetriesNextServer: 2 # 对同一服务不同实例重试次数(同一服务下集群个数的重试次数)
MaxAutoRetries: 2 # 对同一实例重试的次数(单个集群节点服务重试的次数)
# 开启熔断机制,超过六秒即开启熔断机制,网关内的时间排序:zuul的通信时间 > hystrix熔断时间 > retry重试时间
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 6000
4.1测试网关的转发功能:
访问:(服务名:producer-service,被调用服务端口1081,网关端口1085),加网关以后所有请求直接访问网关,经过网关找到访问路径,然后负载找到对应的服务,进行请求转发:
未网关前的访问路径是:http://localhost:1081/hello/hello1
加网关后的访问路径变成了:http://localhost:1085/api/producer-service/hello/hello1
服务接口:
4.2
测试网关的过滤功能,根据用户是否携带token来判断用户是否登录,然后根据用户是否登录来进行下一步的操作
package com.example.lqzuul.config;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
/**
* 编辑ZuulFilter自定义过滤器,用于校验登录
* 重写zuulFilter类,有四个重要的方法
* 1.- `shouldFilter`:返回一个`Boolean`值,判断该过滤器是否需要执行。返回true执行,返回false不执行。
* 2.- `run`:过滤器的具体业务逻辑。
* 3.- `filterType`:返回字符串,代表过滤器的类型。包含以下4种:
* - `pre`:请求在被路由之前执行
* - `routing`:在路由请求时调用
* - `post`:在routing和errror过滤器之后调用
* - `error`:处理请求时发生错误调用
* 4.- `filterOrder`:通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高
*
*
* @author chengxi
* @date 2018/12/5 17:24
*/
@Component
public class LoginFilter extends ZuulFilter {
@Override
public String filterType() {
// 登录校验的过滤级别,肯定是第一层过滤
return "pre";
}
@Override
public int filterOrder() {
// 执行顺序为1,值越小执行顺行越靠前
return 1;
}
@Override
public boolean shouldFilter() {
// 默认此类过滤器时false,不开启的,需要改为true
return true;
}
/**
* 登录校验过滤器,执行逻辑的方法
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
// 登录校验逻辑
// 1)获取zuul提供的请求上下文对象(即是请求全部内容)
RequestContext currentContext = RequestContext.getCurrentContext();
// 2) 从上下文中获取request对象
HttpServletRequest request = currentContext.getRequest();
// 3) 从请求中获取token
//String token = request.getParameter("access-token");
//假设正常登陆
String token = "正常登陆";
// 4) 判断(如果没有token,认为用户还没有登录,返回401状态码)
if(token == null || "".equals(token.trim())){
// 没有token,认为登录校验失败,进行拦截
currentContext.setSendZuulResponse(false);
// 返回401状态码。也可以考虑重定向到登录页
currentContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
}
// 如果校验通过,可以考虑吧用户信息放入上下文,继续向后执行
return request;
}
}