Zuul API 网关

文章目录

Zuul API 网关

统一的入口
统一的权限校验
集成Ribbon
集成Hystrix

统一的入口

  1. 新建spring模块: sp06-zuul
  2. 添加依赖:
    zuul
    sp01
    eureka
    继承springcloud1
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<parent>
		<artifactId>springcloud1</artifactId>
		<groupId>cn.tedu</groupId>
		<version>1.0-SNAPSHOT</version>
	</parent>
	<modelVersion>4.0.0</modelVersion>

	<groupId>cn.tedu</groupId>
	<artifactId>sp06-zuul</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>sp06-zuul</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>
		<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-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>cn.tedu</groupId>
			<artifactId>sp01-commons</artifactId>
			<version>1.0-SNAPSHOT</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>
  1. yml
spring:
  application:
    name: zuul
server:
  port: 3001

# eureka注册中心配置
eureka:
  client:
    service-url:
      # 可以从云服务商购买不同地点的eureka服务器
      # 这里可以改成云服务商提供的地点
      # 自己的服务器只能写defaultZone
      defaultZone: http://eureka1:2001/eureka,http://eureka2:2002/eureka
转发规则: 
# zuul网关配置
zuul: 
	routes: 
		# **包含深层子路径
		# *只包含一层路径
		# service-id作为访问子路径,是默认设置
		# 根据注册表中的注册信息,zuul可以自动配置
		# 最好自己手动配置,防止注册表不全
		item-service: /item-service/**
		user-service: /user-service/**
		order-service: /order-service/**
  1. 启动类注解: @EnableZuulProxy
package cn.tedu.sp06;

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

@EnableZuulProxy
@SpringBootApplication
public class Sp06ZuulApplication {

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

}

统一的权限校验

zuul的过滤器 ZuulProxy,可以过滤客户端请求,在过滤器中可以检查访问权限
http://localhost:3001/item-service/asfdf 没有登陆,不允许访问
http://localhost:3001/item-service/asfdf?token=s4y431 已登录,允许访问

  1. 新建过滤器类: AccessFilter 按照 Zuul 的规则实现
    新建AccessFilter过滤器类,继承ZuulFilter,实现方法,根据业务重写方法
package cn.tedu.sp06.filter;

import cn.tedu.web.util.JsonResult;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

@Component
public class AccessFilter extends ZuulFilter {
    /*设置过滤器的类型:
    * pre(前置过滤器),routing(路由过滤器),post,error
    * */
    @Override
    public String filterType() {
//        return "per";//直接输入过滤器名设置过滤器类型
        return FilterConstants.PRE_TYPE;//调用常量设置过滤器类型
    }

    /* 设置顺序号(默认过滤器有五个,自己创建的过滤器要插入到那个位置,就填第几个)
    */
    @Override
    public int filterOrder() {
        //前置过滤器有五个默认的过滤器,从1开始--5结束
        return 6; //把自己的过滤器放置到末尾
    }

    /* 针对当前请求,是否要执行下面的过滤代码 */
    @Override
    public boolean shouldFilter() {
        /*
        调用商品需要检查权限
        调用用户或订单不检查权限
         */
        //1. 需要获得一个请求上下文对象
        RequestContext ctx = RequestContext.getCurrentContext();
        //2. 从上下文对象中获得调用的后台服务的serviceId
        String serviceId =(String) ctx.get(FilterConstants.SERVICE_ID_KEY);
        //3. 如果调用的是item-service,就返回true
        return serviceId.equals("item-service");
    }

    /* 过滤代码 (权限判断你在这里写)*/
    @Override
    public Object run() throws ZuulException {
        //http://localhost:3001/item-service/asfdf?token=s4y431
        // 获得上下文对象
        RequestContext ctx = RequestContext.getCurrentContext();
        // 获得request对象(用获得request对象接收token参数)
        HttpServletRequest request = ctx.getRequest();
        // 接收token参数
        String token = request.getParameter("token");
        // 如果token不存在
        if (StringUtils.isBlank(token)){
        // 阻止继续调用
            ctx.setSendZuulResponse(false);
        // 直接返回响应
        // JsonResult - {code: 400 ,msg: 未登录, data : null}
            String json = JsonResult.build().code(400).msg("未登录").toString();
            ctx.addZuulResponseHeader("Content-Type", "application/json;charset=UTF-8");
            ctx.setResponseBody(json);
        }

        return null;//zuul当前版本,这个返回值不起任何作用
    }
}

  1. 添加注解@Component
    zuul的自动配置,会在spring容器中发现过滤实例,完成自动配置

Zuul 集成 Ribbon

  • 负载均衡默认启用
  • 重试默认禁用
    在最前面重试,可能造成后台服务器大面积压力倍增,大面积出现故障
  • 启用重试
    1. 添加spring-retry依赖
      <dependency>
      	<groupId>org.springframework.retry</groupId>
      	<artifactId>spring-retry</artifactId>
      </dependency>
      
    2. yml配置启用重试: zuul.retryable=true
# zuul网关配置
zuul:
 routes:
  # **包含深层子路径
  # *只包含一层路径
  # service-id作为访问子路径,是默认设置
  # 根据注册表中的注册信息,zuul可以自动配置
  # 最好自己手动配置,防止注册表不全
   item-service: /item-service/**
   user-service: /user-service/**
   order-service: /order-service/**
 retryable: true
3. 如果需要可以配置重试参数

Zuul 集成 Hystrix

Hystrix是容错和限流工具

  • Hystrix容错: 降级
  • Hystrix限流: 熔断

Zuul 网关使用Hystrix进行容错处理,执行降级
zuul默认已经启用Hystrix ,任何基础配置都不用做

调用后台服务失败,执行前面模块中的降级代码,向客户端返回降级结果

  • 错误提示
  • 缓存数据
  • 根据业务逻辑,返回任何结果都可以
  1. 新建降级类: ItemFB,实现 FallbackProvider 接口
package cn.tedu.sp06.fb;

import cn.tedu.web.util.JsonResult;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

@Component
public class ItemFB implements FallbackProvider {
    /*
    设置针对哪个后台服务进行降级
    - item-service: 只对商品服务降级
    - *:    对所有服务都应用当前降级类
    - null: 对所有服务都应用当前降级类
     */
    @Override
    public String getRoute() {
        return "item-service"; //只对商品服务降级
    }

    /*
    向客户端返回的响应数据
     */
    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        return new ClientHttpResponse() { // 包含响应数据
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.INTERNAL_SERVER_ERROR; //返回给客户端的数据
            }

            @Override
            public int getRawStatusCode() throws IOException {
                return HttpStatus.INTERNAL_SERVER_ERROR.value(); //响应数据key(200/500/)
            }

            @Override
            public String getStatusText() throws IOException {
                return HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase(); //文本字符串
            }

            @Override
            public void close() {
                //用来关闭下面的流
                //ByteArrayInputStream不占用底层系统资源,不需要关闭
            }

            @Override
            public InputStream getBody() throws IOException { //协议体
                // JsonResult -{code: 500, msg:xxx data: null}
                String json = JsonResult
                        .build()
                        .code(500)
                        .msg("后台服务出错,请稍后重试")
                        .toString();
                //字符串变成byte[]数组,封装到ByteArrayInputStream
                return new ByteArrayInputStream(json.getBytes("UTF-8"));
            }

            @Override
            public HttpHeaders getHeaders() { //协议头
                HttpHeaders headers = new HttpHeaders();
                headers.add("Content-Type", "application/json;charset=UTF-8");
                return headers;
            }
        };
    }
}
  1. 添加注解: @Component
  • zuul的自动配置,可以自动发现降级类实例,完成自动配置

zuul集成Hystrix实现限流,熔断
当流量过大,后台服务出现故障,可以断开线路,限制后台故障服务的流量,等待他从故障中恢复

  • 断路器打开条件:
    1. 条件一: 默认是10秒20次请求(必须首先满足)
    2. 条件二: 50%请求出错,执行了降级代码
  • 断路器打开后,会进入半开状态
    在半开状态下,会向后台服务尝试发送一次客户端调用.
    调用成功自动关闭断路器,恢复正常.
    调用失败,继续保持打开状态
上一篇:springboot springcloud zuul 过滤器


下一篇:SpringCloud学习笔记2