spring-boot版本:2.0.4.RELEASE,spring-cloud版本:Finchley.RELEASE,java版本:1.8
一、快速启动一个zuul
1.新建一个父项目,依赖如下
<?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.taikang.bd</groupId>
<artifactId>spring-cloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging><!--声明pom为父-->
<!--子项目-->
<modules>
<module>eureka-8761</module>
<module>zuul-8800</module>
<module>myservice-9001</module>
</modules>
<!--项目名和描述-->
<name>SpringCloud</name>
<description>This is a Spring project</description>
<!--父依赖-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.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>
<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--spring boot web依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--spring boot 启动依赖,集成好多依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--spring boot 测试依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!--spring cloud 管理-->
<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-server,引入依赖
<!--eureka-server的核心依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!--其他基本依赖,父项目有了已经-->
配置文件:
spring:
application:
name: eureka-server
server:
port: 8761
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
register-with-eureka: false #不注册自己
fetch-registry: false
然后主启动类
@SpringBootApplication
@EnableEurekaServer
public class EurekaServer {
public static void main(String[] args) {
SpringApplication.run(EurekaServer.class,args);
}
}
2.然后写一个简单的微服务,作为eureka的客户端注册到eureka
新建子项目my-service,引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
配置文件
server:
port: 9001
spring:
application:
name: my-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
新建一个controller
@RestController
public class HelloController {
@Value("${server.port}")
private String port;
@GetMapping("/hi")
public String hello(){
return "hello,The port is :"+port;
}
}
主启动类
@SpringBootApplication
@EnableDiscoveryClient //注册到eureka
public class MyService {
public static void main(String[] args) {
SpringApplication.run(MyService.class,args);
}
}
3.接下来新建子项目zuul-server,引入依赖
<!--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-security</artifactId>
</dependency>
zuul的配置文件,如下设置的安全密码在访问路由的时候需要验证
spring:
application:
name: zuul-server
security: #设置安全密码
user:
name: root
password: root
server:
port: 8800
eureka: #只有注册到了eureka才可以发现服务,才可以访问
client:
service-url:
defaultZone: http://localhost:8761/eureka/
zuul的启动类:
@SpringBootApplication
@EnableZuulProxy //开启网关服务功能,默认注册到eureka
public class ZuulServer {
public static void main(String[] args) {
SpringApplication.run(ZuulServer.class,args);
}
}
zuul的配置文件暂时还没有设置路由,浏览器输入localhost:8800/my-service/hi 即可访问到。
在这里我的服务名是my-service,我的请求路径是/hi。
3.1配置下路由信息:
spring:
application:
name: zuul-server
security: #设置安全密码
user:
name: root
password: root
server:
port: 8800
eureka: #只有注册到了eureka才可以发现服务,才可以访问
client:
service-url:
defaultZone: http://localhost:8761/eureka/
zuul:
routes:
route-1: #路由名,保证唯一即可
path: /163
#sensitiveHeaders: Cookie,Set-Cookie,Authorization #不传递请求头的一些信息
url: http://www.163.com #也可以写 forward:转发,后面跟上url
route-2:
path: /app/** #表示这个服务下的所有接口都可以访问
serviceId: my-service #你注册到eureka的服务名,如果这你指定的是url,那他就没有ribbon和hystrix了
legacy: #其他服务这样访问
path: /**
prefix: /qz #配置一个前缀,访问路由都得带上这个
ignore-security-headers: false #禁用安全,不会过滤一些请求头
# ignored-services: my-service #不想代理的服务名
#================================
#如果禁用了ribbon,如何做负载均衡
#zuul:
# routes:
# route-1:
# path: /163
# serviceId: my-service
#ribbon:
# eureka:
# enabled: false
#my-service:
# ribbon:
# listOfServers: baidu.com,google.com
spring:
application:
name: zuul-server
security: #设置安全密码
user:
name: root
password: root
server:
port: 8800
eureka: #只有注册到了eureka才可以发现服务,才可以访问
client:
service-url:
defaultZone: http://localhost:8761/eureka/
zuul:
routes:
route-1: #路由名,保证唯一即可
path: /163
#sensitiveHeaders: Cookie,Set-Cookie,Authorization #不传递请求头的一些信息
url: http://www.163.com #也可以写 forward:转发,后面跟上url
route-2:
path: /app/** #表示这个服务下的所有接口都可以访问
serviceId: my-service #你注册到eureka的服务名,如果这你指定的是url,那他就没有ribbon和hystrix了
# legacy: #其他服务这样访问
# path: /**
# prefix: /qz #配置一个前缀,访问路由都得带上这个
# ignore-security-headers: false #禁用安全,不会过滤一些请求头
# ignored-services: my-service #不想代理的服务名
#================================
#如果禁用了ribbon,如何做负载均衡
#zuul:
# routes:
# route-1:
# path: /163
# serviceId: my-service
#ribbon:
# eureka:
# enabled: false
#my-service:
# ribbon:
# listOfServers: baidu.com,google.com
4.zuul的fallback功能
只需实现一个接口即可
@Component
public class MyZuulFacllBack implements FallbackProvider {
@Override
public String getRoute() {
return "my-service";//服务id,如果需要所有服务支持回退就return "*"或return null
}
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
return 200;
}
@Override
public String getStatusText() throws IOException {
return "OK";
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream("The service is unavailable.".getBytes());
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
};
}
}
如果一个服务网挂掉了,他将返回the service is unavailable。
5.zuul的过滤器
临时先写个简单的,明天做jwt鉴权
package com.taikang.bd.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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
public class MyZuulFilter extends ZuulFilter {
private Logger logger = LoggerFactory.getLogger(MyZuulFilter.class);
@Override
public String filterType() {
return "pre";//4种,pre 在之前执行 post error routing
}
@Override
public int filterOrder() {
return 0;//数字越小,优先级越高
}
@Override
public boolean shouldFilter() {
return true;//true 表示执行这个过滤器,false表示不执行
}
@Override
public Object run() throws ZuulException {//执行过滤的逻辑
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String token = request.getParameter("token");// 获取请求的参数
logger.info("---------------------token is --------------------"+ token);
if (StringUtils.isNotBlank(token)) {
ctx.setSendZuulResponse(true); //对请求进行路由
ctx.setResponseStatusCode(200);
ctx.set("isSuccess", true);
return null;
} else {
ctx.setSendZuulResponse(false); //不对其进行路由
ctx.setResponseStatusCode(400);
ctx.setResponseBody("token is empty");
ctx.set("isSuccess", false);
return null;
}
}
}