父工程的SpringBoot版本需要降级到2.0.7的,如果超过了会不兼容.

| <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.0.7.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency> | | —- |


新建立一个模块【microcloud-zuul-gateway】
【microcloud-zuul-gateway】 的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”
>
<parent>
<artifactId>ZJJ_SpringCloud</artifactId>
<groupId>com.zjj</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>microcloud-zuul-gateway</artifactId>


<dependencies>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.1.8.RELEASE</version>
</dependency>

<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-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
</project> | | —- |




【microcloud-zuul-gateway】修改application.yml文件

| server:
port: 9501

eureka:
client: # 客户端进行Eureka注册的配置 service-url:
defaultZone: http://admin:enjoy@localhost:7001/eureka
register-with-eureka: false
instance:
instance-id: microcloud-zuul-gateway
prefer-ip-address: true
lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒) lease-expiration-duration-in-seconds: 5 # 如果现在超过了5秒的间隔(默认是90秒)
spring:
application:
name: microcloud-zuul-gateway
security:
user:
name: admin
password: enjoy | | —- |


【microcloud-zuul-gateway】 创建启动类

| 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);
}


} | | —- |

1.Zuul过滤器和SpringSecurity配置

配置SpringSecurity保护接口安全信息,
前面yml已经添加了SpringSecurity账号密码,然后项目已经引入了spring-boot-starter-security 依赖,需要配置过滤器

| import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;

import java.nio.charset.Charset;
import java.util.Base64;


/**

  • 自定义zuul过滤器 /
    public class AuthorizedRequestFilter extends ZuulFilter {
    /*

    • 配置前缀过滤器,是请求发送之前过滤的
    • @return
      *
      /
      @Override
      public String filterType() {
      return FilterConstants.PRE_TYPE;
      }

      @Override
      public int filterOrder() {
      return 0;
      }

      @Override
      public boolean shouldFilter() {
      return true;
      }
      /配置访问服务的生产者的密码/


      @Override
      public Object run() throws ZuulException {
      RequestContext currentContext = RequestContext.getCurrentContext(); // 获取当前请求的上下文 String auth = “admin:enjoy”; // 认证的原始信息 byte[] encodedAuth = Base64.getEncoder()
      1. .encode(auth.getBytes(Charset._forName_(**"US-ASCII"**))); // 进行一个加密的处理
      String authHeader = “Basic “ + new String(encodedAuth);
      currentContext.addZuulRequestHeader(“Authorization”, authHeader);

      return null;
      }
      } | | —- |


    其中filterType为过滤的类型
    在进行Zuul过滤的时候可以设置其过滤执行的位置,那么此时有如下几种类型:
    l pre:在请求发出之前执行过滤,如果要进行访问,肯定在请求前设置头信息
    l route:在进行路由请求的时候被调用;
    l post:在路由之后发送请求信息的时候被调用;
    l error:出现错误之后进行调用

| import com.filter.AuthorizedRequestFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ZuulConfig {
/**

  1. * 让过滤器生效 给过滤器加入到Spring容器里面
  2. * **@return<br />
  3. ***/<br />

@Bean
public AuthorizedRequestFilter getAuthorizedRequestFilter() {
return new AuthorizedRequestFilter();
}
} | | —- |


然后启动 Eureka服务和microcloud-provider-product服务和这个Zuul服务



正常访问用户服务:http://localhost:8080/prodcut/list
使用zuul代理访问用户服务:http://localhost:9501/microcloud-provider-product/prodcut/list
zuul代理访问规则是 zuul的 ip + 端口 + EurekaApplication名字(大小写无所谓)+RequestMapping映射

2.Zuul配置路由

前面以及简单的使用了zuul,但你会发现访问地址还必须知道程序的名称,如果不知道这个名称是无法访问的,但如果让用户知道了这名称,那么使用zuul就是去它的实际意义的,我们可以通过名称直接调用

既然是使用代理,那么代理的功能就是不能让用户看到真实的操作,屏蔽真实的调用地址(Eureka的Application名字),这个时候就需要自己增加zuul的路由规则配置了。


【microcloud-zuul-gateway】修改application.yml配置文件,增加路由配置

| # MICROCLOUD-PROVIDER-PRODUCT 是Eureka的Application名字 zuul:
routes:
MICROCLOUD-PROVIDER-PRODUCT: /users-proxy/** | | —- |


http://localhost:8080/prodcut/list 原来的服务
http://localhost:9501/microcloud-provider-product/prodcut/list zuul通过Eureka的Application服务访问的
http://localhost:9501/users-proxy/prodcut/list 通过zuul服务路由访问的



如果出现了这个错误
com.netflix.client.ClientException: Load balancer does not have available server for client: **
就是没开feign或者RestTemplate的Consumer的项目,

如果想禁止zuul通过 Eureka的Application名字访问的话
http://localhost:9501/microcloud-provider-product/prodcut/list

【microcloud-zuul-gateway】修改application.yml文件,忽略掉用户服务的名称

| zuul:
routes:
MICROCLOUD-PROVIDER-PRODUCT: /users-proxy/**

  1. # 禁止zuul通过Eureka的application名字去访问,注意要小写
  2. # 大写会失效

ignored-services:
“microcloud-provider-product” | | —- |


做完后,就可以进行代理的安全使用,但真实情况下,一般会有很多微服务,如果完全按照上面的配置方式会非常的麻烦,所有最加到的做法是可以采用一个通配符“*”的模式来统一完成。

【microcloud-zuul-gateway】修改application.yml文件

| zuul:
routes:
MICROCLOUD-PROVIDER-PRODUCT: /users-proxy/**

  1. # *匹配全部 <br />

ignored-services:
“*” | | —- |



除开上面这一种访问模式以外,在zuul中还有另外一种配置方式
【microcloud-zuul-gateway】修改application.yml文件
zuul:
routes:
users.path: /users-proxy/*
users.serviceId: microcloud-provider-users
ignored-services:


其中在配置文件中出现的users其实是一个逻辑名称,这个名称主要作用是将path与serviceId绑定在一起

【microcloud-zuul-gateway】如果说不想通过eureka进行访问,对于zuul来说也是可以实现的,但是在真实的开发环境中,基本不会使用

| zuul:
routes:
users:

经过Eureka路由

  1. **path**: /users-proxy/**<br />
  2. **serviceId**: microcloud-provider-users<br />
  3. **users2**:<br />

ZUUL也可以不经过Eureka 直接路由 ,功能类似nginx一样

  1. **path**: /users2-proxy/**<br />
  2. **url**: http://localhost:8090/<br />
  3. **product**:<br />
  4. **path**: /product-proxy/**<br />
  5. **serviceId**: microcloud-provider-product<br />
  6. # 配置忽略的服务,这样就不能通过访问Eureka的Application名字访问项目了,<br />
  7. #意思就是ZUUL + Application名字 就不能访问了.<br />
  8. # * 是匹配所有

ignored-services:
“*”
# 可以在url前面加个统一的前缀,通过zuul调用的时候就需要加这个前缀了.
prefix: /enjoy-api | | —- |


【microcloud-zuul-gateway】 设置公共前缀

zuul:
routes:
users:# 经过Eureka路由 path: /users-proxy/
serviceId: microcloud-provider-users
users2:# ZUUL也可以不经过Eureka 直接路由 ,功能类似nginx一样 path: /users2-proxy/
url: http://localhost:8090/
product:
path: /product-proxy/
serviceId: microcloud-provider-product
# 配置忽略的服务,这样就不能通过访问Eureka的Application名字访问项目了,
#意思就是ZUUL + Application名字 就不能访问了.
# * 是匹配所有
ignored-services:
“*# 可以在url前面加个统一的前缀,通过zuul调用的时候就需要加这个前缀了. prefix: /enjoy-api


一旦设置了公共前缀,所以的访问路径都要在前面加上前缀enjoy-api/
http://localhost:9501/enjoy-api/users-proxy/prodcut/list

3.zuul 过滤访问

其实zuul的功能本质上就是一个代理操作,类似于nginx,但是在真实的使用中,所有的微服务一点都有增加的认证信息,那么就必须在其访问之前追加认证的头部操作,这样的功能需要通过zuul的过去操作完成。

【microcloud-zuul-gateway】 修改application.yml配置,增加产品微服务
zuul:
routes:
users:
path: /users-proxy/
serviceId: microcloud-provider-users
users2:
path: /users2-proxy/

url: http://localhost:8090/
product:
path: /product-proxy/*
serviceId: microcloud-provider-product
ignored-services:

prefix: /enjoy-api

这样直接访问:http://localhost:9501/enjoy-api/product-proxy/prodcut/get/1
这样是访问不到的

【microcloud-zuul-gateway】追加过滤处理
package cn.enjoy.filter;


import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;

import java.nio.charset.Charset;
import java.util.Base64;

public class AuthorizedRequestFilter extends ZuulFilter{
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return 0;
}

@Override
public boolean shouldFilter() {
return true;
}

@Override
public Object run() throws ZuulException {
RequestContext currentContext = RequestContext.getCurrentContext() ; // 获取当前请求的上下文
String auth = “admin:enjoy”; // 认证的原始信息
byte[] encodedAuth = Base64.getEncoder()
.encode(auth.getBytes(Charset.forName(“US-ASCII”))); // 进行一个加密的处理
String authHeader = “Basic “ + new String(encodedAuth);
currentContext.addZuulRequestHeader(“Authorization”, authHeader);
return null;
}
}

其中filterType为过滤的类型
在进行Zuul过滤的时候可以设置其过滤执行的位置,那么此时有如下几种类型:
l pre:在请求发出之前执行过滤,如果要进行访问,肯定在请求前设置头信息
l route:在进行路由请求的时候被调用;
l post:在路由之后发送请求信息的时候被调用;
l error:出现错误之后进行调用

【microcloud-zuul-gateway】建立一个配置程序类
package cn.enjoy.config;

import cn.enjoy.filter.AuthorizedRequestFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class ZuulConfig {
@Bean
public AuthorizedRequestFilter getAuthorizedRequestFilter() {
return new AuthorizedRequestFilter() ;
}
}

这个时候访问:
http://localhost:9501/enjoy-api/product-proxy/prodcut/get/1
http://localhost:9501/enjoy-api/users-proxy/users/get/1

这两个服务都能正常访问了。

4.Zuul安全访问

作为所有接口的统一门面,zuul也是可以进行加密访问的
【microcloud-zuul-gateway】修改pom文件,增加安全访问模块

可能需要版本号.

org.springframework.boot
spring-boot-starter-security


【microcloud-zuul-gateway】修改application.yml配置文件,增加用户配置
spring:
application:
name: microcloud-zuul-gateway
security:
user:
name: admin
password: enjoy

再访问http://localhost:9501/enjoy-api/users-proxy/users/get/1
这个时候就需要输入用户名密码了

5.Feign访问Zuul同时配置容错处理

前面学习feign的时候确实已经知道,他其实是去eureka中获取服务地址的,如果想使用feign来访问zuul,首先就应该让zuul注册到eureka中
【microcloud-zuul-gateway】 修改application.yml文件

| eureka:
client: # 客户端进行Eureka注册的配置 service-url:
defaultZone: http://admin:enjoy@localhost:7001/eureka

register-with-eureka: false # 如果是false就不能加入到Eureka里面

instance:
instance-id: microcloud-zuul-gateway
prefer-ip-address: true
lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒) lease-expiration-duration-in-seconds: 5 # 如果现在超过了5秒的间隔(默认是90秒) | | —- |


03.基本使用 - 图1

【microcloud-service】现在所有的服务要通过zuul的代理进行访问,新增接口

package cn.enjoy.service;

import cn.enjoy.feign.FeignClientConfig;
import cn.enjoy.service.fallback.IProductClientServiceFallbackFactory;
import cn.enjoy.service.fallback.IZUUlClientServiceallbackFactory;
import cn.enjoy.vo.Product;
import cn.enjoy.vo.Users;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

@FeignClient(name = “MICROCLOUD-ZUUL-GATEWAY”,configuration = FeignClientConfig.class,
fallbackFactory = IZUUlClientServiceallbackFactory.class)
public interface IZUUlClientService {

@RequestMapping(“/enjoy-api/product-proxy/prodcut/get/{id}”)
public Product getProduct(@PathVariable(“id”)long id);

@RequestMapping(“/enjoy-api/product-proxy/prodcut/list”)
public List listProduct() ;

@RequestMapping(“/enjoy-api/product-proxy/prodcut/add”)
public boolean addPorduct(Product product) ;

@RequestMapping(“/enjoy-api/users-proxy/users/get/{name}”)
public Users getUsers(@PathVariable(“name”)String name);
}


新增IZUUlClientServiceallbackFactory,在Zuul由于出现网络问题失去联系后进行容错处理
package cn.enjoy.service.fallback;


import cn.enjoy.service.IProductClientService;
import cn.enjoy.service.IZUUlClientService;
import cn.enjoy.vo.Product;
import cn.enjoy.vo.Users;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class IZUUlClientServiceallbackFactory implements FallbackFactory {
@Override
public IZUUlClientService create(Throwable throwable) {
return new IZUUlClientService() {
@Override
public Product getProduct(long id) {
Product product = new Product();
product.setProductId(999999L);
product.setProductName(“feign-zuulName”);
product.setProductDesc(“feign-zuulDesc”);
return product;
}

@Override
public List listProduct() {
return null;
}

@Override
public boolean addPorduct(Product product) {
return false;
}

@Override
public Users getUsers(String name) {
Users user = new Users();
user.setSex(“F”);
user.setAge(17);
user.setName(“zuul-fllback:”+name);
return user;
}
};
}
}



【microcloud-consumer-hystrix】 修改ConsumerProductController,增加一个新的方法,访问接口
package cn.enjoy.controller;


import cn.enjoy.service.IProductClientService;
import cn.enjoy.service.IZUUlClientService;
import cn.enjoy.vo.Product;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping(“/consumer”)
public class ConsumerProductController {

@Resource
private IProductClientService iProductClientService;

@Resource
private IZUUlClientService izuUlClientService;


@RequestMapping(“/product/get”)
public Object getProduct(long id) {
return iProductClientService.getProduct(id);
}

@RequestMapping(“/product/list”)
public Object listProduct() {
return iProductClientService.listProduct();
}

@RequestMapping(“/product/add”)
public Object addPorduct(Product product) {
return iProductClientService.addPorduct(product);
}

@RequestMapping(“/product/getProductAndUser”)
public Object getProductAndUser(long id) {
Map result = new HashMap();
result.put(“product”,izuUlClientService.getProduct(id));
result.put(“user”,izuUlClientService.getUsers(id+””));
return result;
}
}


依次启动eureka,user服务,product服务,zuul服务,customerhystrix服务
03.基本使用 - 图2

在地址栏输入:
http://localhost/consumer/product/getProductAndUser?id=1

关闭zuul服务
http://localhost/consumer/product/getProductAndUser?id=1

发现服务降级已经开启