springCloud初识5-网关 Zuul

Zuul是Netlix开源的微服务网关,它可以和Eureka、Ribbon、 Hystrix 等组件配合使用。
Zuul的核心是一系列的过滤器,这些过滤器可以完成以下功能。

  • 身份认证与安全:识别每个资源的验证要求,并拒绝那些与要求不符的请求。
  • 审查与监控:在边缘位置追踪有意义的数据和统计结果,从而带来精确的生产视图。
  • 动态路由:动态地将请求路由到不同的后端集群。
  • 压力测试:逐渐增加指向集群的流量,以了解性能。
  • 负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求。
  • 静态响应处理:在边缘位置直接建立部分响应,从而避免其转发到内部集群。
  • 多区域弹性:跨越AWS Region进行请求路由,旨在实现ELB ( Elastic Load Balancing)使用的多样化,以及让系统的边缘更贴近系统的使用者。

Spring Cloud对Zuul进行了整合与增强。目前,Zuul使用的默认HTTP客户端是Apache HTTP Client,也可以使用RestClient或者okhttp3.0kHttpClient。
如果想要使用RestClient,可以设置ribbon.restclient.enabled=true;想要使用okhttp3.0kHttpClient,可以设置ribbon.okhttp.enabled=true。

路由:分发给不同的微服务(通过服务名)
负载均衡:分发同一个微服务的不同实例,减少单个压力

zuul4种配置方式

配置方式1:快速入门 (只是做了路径分发 通过路径可路由)

1--新建项目,引入依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>

2--覆盖默认配置

server:  # 设置应用端口
  port: 10010
spring:  # 设置应用即微服务名称
  application:
    name: xiaoai_zuul

3--引导类启用zuul组件

package com.xiaoai.zuul;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@SpringBootApplication
@EnableZuulProxy  //启用zuul组件
public class XiaoaiZuulApplication {

	public static void main(String[] args) {
		SpringApplication.run(XiaoaiZuulApplication.class, args);
	}
}

4--配置路由

zuul:
  routes:
    service-provider: # 路由名称,可以随便写,习惯上用服务的名称,即之前自己定义的某个服务的名称。
      path: /service-provider/**
      url: http://localhost:8081

--通过zuul访问配置好的服务,可以正常访问

--如未配置消费端路由,zuul访问其url

--配置消费服务端路由后,zuul访问其url

server:
  port: 10010
spring:
  application:
    name: xiaoai_zuul

zuul:
  routes:
    service-provider:** # 路由名称,可以随便写,习惯上用服务的名称,即之前自己定义的某个服务的名称。
      path: /service-provider/**
      url: http://localhost:8081
    service-consumer: # 配置消费端路由
      path: /service-consumer/**
      url: http://localhost:80

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:10086/eureka

配置方式2:zuul注册到eureka容器 (通过服务id可路由)

1--引入eureka启动器

<!--引入eureka-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

2--把zuul注入eureka容器中,application配置文件配置

spring:
  application:
    name: xiaoai_zuul

eureka:
  client:
    service-url:
      defaultZone: http/localhost:10086/eureka

3--引导类启用eureka

package com.xiaoai.zuul;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@SpringBootApplication
@EnableZuulProxy  //启用zuul组件
@EnableDiscoveryClient  //启用eureka客户端
public class XiaoaiZuulApplication {

	public static void main(String[] args) {
		SpringApplication.run(XiaoaiZuulApplication.class, args);
	}

}

4--配置文件可以修改路由,直接配置服务id即可

server:
  port: 10010
spring:
  application:
    name: xiaoai_zuul

zuul:
  routes:
    service-provider: # 路由名称,可以随便写,习惯上用服务的名称,即之前自己定义的某个服务的名称。
      path: /service-provider/**
#      url: http://localhost:8081  # 写死端口无法负载均衡
      serviceId: service-provider  # 把zuul注入到了eureka后,其可以拉取客户端服务,所以可以直接写服务id,即自己定义的名称,通过服务id,zuul也可以实现负载均衡

eureka:
  client:
    service-url:
      defaultZone: http//localhost:10086/eureka

--zuul访问提供服务端url可以正常访问

配置方式3:路径直接配置在服务id后

--application配置文件配置

server:
  port: 10010
spring:
  application:
    name: xiaoai_zuul

zuul:
  routes:
    service-provider: /service-provider/** # 路由名称,可以随便写,习惯上用服务的名称,即之前自己定义的某个服务的名称。
#      path: /service-provider/**
#      url: http://localhost:8081
#      serviceId: service-provider  # 把zuul注入到了eureka后,其可以拉取客户端服务,所以可以直接写服务id,即自己定义的名称,通过服务idzuul也可以实现负载均衡

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:10086/eureka

--访问

配置方式4: 加入eureka容器后 不配置任何路由 默认访问就是服务名加路径

--配置如下

server:
  port: 10010
spring:
  application:
    name: xiaoai_zuul

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:10086/eureka

--访问

默认使用第三种配置方式,使用第三种可以修改路径 简化路径前缀 如配置:

server:
  port: 10010
spring:
  application:
    name: xiaoai_zuul

zuul:
  routes:
    service-provider: /user/** # 路由名称,可以随便写,习惯上用服务的名称,即之前自己定义的某个服务的名称。 路径可以使用服务id也可以修改自定义,这里改为user
    service-consumer: /consumer/**

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:10086/eureka

--访问

在某个微服务中控制器减少一层路径 如提供端服务service-provider的控制类

package com.xiaoai.service.controller;

import com.xiaoai.service.pojo.User;
import com.xiaoai.service.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("{id}")
    public User queryUserById(@PathVariable("id")Long id) {
        return this.userService.queryUserById(id);
    }

}

zuul的application配置文件

server:
  port: 10010
spring:
  application:
    name: xiaoai_zuul
zuul:
  routes:
    service-provider: /user/** # 路由名称,可以随便写,习惯上用服务的名称,即之前自己定义的某个服务的名称。
    service-consumer: /consumer/**
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:10086/eureka

--访问

网关前缀

由于项目发布以后无法知道访问路径是否经过网关,可以在application配置文件中配置加入前缀来区分访问是否经过网关。如:

server:
  port: 10010
spring:
  application:
    name: xiaoai_zuul

zuul:
  routes:
    service-provider: /user/** # 路由名称,可以随便写,习惯上用服务的名称,即之前自己定义的某个服务的名称。
    service-consumer: /consumer/**
    prefix: /api # 前缀用于区分访问是否经过网关,这里为api,可以自定义,默认一般使用api
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:10086/eureka

--访问

小结

  • 引入zuul的启动器
  • 配置:
    • zuul.routes.<路由名称>.path=/service-provider/** zuul.routes.<路由名称>.url=http://localhosta:8081
    • zuul.routes.<路由名称>.path=/service-provider/** zuul.routes.<路由名称>.serviceId=service-provider
    • zuul.routes.服务名称=/service-provider/**
    • 不用配置,默认就是服务id+路径
  • 引导类注解@EnableZuulProxy 开启zuul
  • 引导类@EnableDiscoveryClient 开启eureka客户端

zuul过滤器

Zuul作为网关的其中一个重要功能, 就是实现请求的鉴权。而这个动作我们往往是通过Zuul提供的过滤器来实现

Zuul过滤器需实现接口:IZuulFilter

  • 方法shouldFilter() 返回值true执行run方法,false不执行
  • 方法run() 过滤器业务逻辑的方法,是否拦截在该方法判断
    默认有一些实现了IZuulFilter接口的类

1--定义一个过滤器

package com.xiaoai.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 LoginFilter extends ZuulFilter{


    /**
     * 过滤器类型选择:pro route post error
     * @return
     */
    @Override
    public String filterType() {
        return "pre";
    }

    /**
     * 执行的顺序,返回值越小,优先级越高
     * @return
     */
    @Override
    public int filterOrder() {
        return 10;
    }

    /**
     * 是否执行该过滤器 即run方法
     * true==执行
     * false==不执行
     * @return
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * 编写过滤器的业务逻辑
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
        //初始化context上下文对象,
        RequestContext context = RequestContext.getCurrentContext();
        //获取request对象
        HttpServletRequest request = context.getRequest();
        //获取参数
        String token = (String) request.getParameter("token");
        if (StringUtils.isBlank(token)){
            //拦截 ,这里表示不转发请求
            context.setSendZuulResponse(false);
            //响应状态码,401-身份未认证
            context.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
            //设置响应的提示
            context.setResponseBody("request error!");
        }
        //返回值为null,表示该过滤器什么都不做
        return null;
    }
}

2--访问

springCloud初识小结

  • eureka
    • 注册中心
    • 微服务容器
  • ribbon
    • 负载均衡组件
    • eureka集成 feign集成 zuul集成
    • @LoadBalanced 开启负载均衡
    • this.restTemplate.getForObject("http://service-provider/user/"+id,User.class) 实现负载均衡
  • hystrix
    • 容错组件
    • 降级:检查每次请求,是否请求超时,或连接池已满
      • 引入hystrix启动器
      • 熔断时间,默认1s,
      • 在引导类上添加了一个注解: @EnableCircuitBreaker @SpringCloudApplication
      • 定义熔断方法:局部(要和被熔断的方法返回值和参数列表一致)全局 (返回值类型要被熔断的方法一致, 参数列表必须为空)
        • @HystrixCommand (fallbackMethod="局部熔断方法名"):声明被熔断的方法
        • @DefaultProperties (defaultFallback="全局熔断方法名")
    • 熔断:不再发送请求
      • close:闭合状态,所有请求正常方法
      • open:打开状态,所有请求都无法访问。如果在- -定时间内容,失败的比例不小于508或者次数不少于20次
      • half open: 半开状态,打开状态默认5s休眠期,在休眠期所有请求无法正常访问。过了休眠期会进入半开状态,放部分请求通过
  • feign
    • 引入openFeign启动器
    • feign.hystrix.enable=true,开启feign的熔断功能
    • 在引导类上@EnableFeignClients启用feign
    • 创建一一个接口,在接口添加eFeignClient (value="微服务id", fallback=实现类.class)
    • 在接口中定义一些方法,这些方法的书写方式跟之前controller类似
    • 创建了一个熔断类,实现feign接口,实现对应的方法,这些实现方法就是熔断方法
  • zuul
    • 网关,路由分发
    • 引入zuul的启动器
    • 配置:4种方式
      • zuul.routes.<路由名称>.path=/service-provider/** zuul.routes.<路由名称>.url=http://localhosta:8081
      • zuul.routes.<路由名称>.path=/service-provider/** zuul.routes.<路由名称>.serviceId=service-provider
      • zuul.routes.服务名称=/service-provider/**
      • 不用配置,默认就是服务id+路径
    • 引导类注解@EnableZuulProxy 开启zuul
    • 引导类@EnableDiscoveryClient 开启eureka客户端
    • 过滤器:
      • 创建一个类继承ZuulFilter基类
      • 重写四个方法
        • filterType: pro route post error
        • filterOrder:返回值越小优先值越高
        • shouldFilter:返回值判断是否执行run方法。true=执行 false=不执行
        • run:具体的拦截逻辑
原文地址:https://www.cnblogs.com/xiaoaiying/p/13437092.html