06-微服务网关zuul

2022-07-18

06-微服务网关zuul

微服务网关zuul开发

一. 微服务网关介绍和使用场景

1. 什么是网关

API Gateway,是系统的唯一对外的入口,介于客户端和服务器端之间的中间层,处理非业务功能 提供路由请求、鉴权、监控、缓存、限流等功能

		统一接入
			智能路由
			AB测试、灰度测试
			负载均衡、容灾处理
			日志埋点(类似Nignx日志)

		流量监控
			限流处理
			服务降级

		安全防护
			鉴权处理
			监控
			机器网络隔离

2. 主流的网关

	zuul:是Netflix开源的微服务网关,和Eureka,Ribbon,Hystrix等组件配合使用,Zuul 2.0比1.0的性能提高很多

	kong: 由Mashape公司开源的,基于Nginx的API gateway

	nginx+lua:是一个高性能的HTTP和反向代理服务器,lua是脚本语言,让Nginx执行Lua脚本,并且高并发、非阻塞的处理各种请求

二. springCloud网关组件zuul的基本使用

1. 主要依赖

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

2. 启动类加入注解

	@EnableZuulProxy

3. 访问规则

  1. 默认访问

    http://gateway:port/service-id/**
    例如:localhost:9000/order-service/api/v1/..

  2. 自定义路由转发

    在配置文件中添加
    zuul:
    routes:
    order-service: /order/**

    注意事项

    **代表所有字符包括/
    *代表所有字母数字下划线(不包括/)

    这里有个坑,同一个地址只能被一个服务所用,如果不同服务用了同一路由,前面配置的不能使用,即路由覆盖问题

    有两种配置方式(待定)
    第一种:order-service: /order/**
    第二种: zuul.routes.order.path=/order/**
    zuul.routes.order.serviceId=order-service
    即分别指定service-id和路径

  3. 环境隔离配置

    ignored-patterns: /*-service/** 忽略包含-service的全部请求

    prefix: /apigateway 所有请求前缀必须加上apigateway
    例如:http://localhost:9000/apigateway/product/api/v1/product/list

三. 高级篇幅之Zuul常用问题分析和网关过滤器原理分析

必要时可以查看zuul源码,在ZuulProperties.class中配置

1. 路由名称定义问题

	路由映射重复覆盖问题(见上)

2. Http请求头过滤问题

	如果使用zuul网关,cookie在后台会被zuul过滤掉,可以参考源码所示:

解决方案

	在配置文件中加入如下配置:zuul:
							sensitiveHeaders:
	即将默认的sensitiveHeaders清空

3. 过滤器执行问题

zuul执行流程如下图

	过滤器order越小,越先执行

4. 共享RequestContext,上下文对象

四. 自定义Zuul过滤器实现登陆鉴权

Zuul实际上就是一堆Filter的集合

1. 创建继承了ZuulFilter的自定义类

	public class LoginFilter extends ZuulFilter {}

2. 重写抽象方法,并加注解

	@Component
	public class LoginFilter extends ZuulFilter {
	    @Override
	    public String filterType() {
	        return null;
	    }

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

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

	    @Override
	    public Object run() throws ZuulException {
	        return null;
	    }
	}

3. 分别编写每个方法

	filterType		过滤器类型,分为pre,post,route,error	可以参考FilterConstants这个类
	filterOrder		过滤器顺序,越小越先执行
	shouldFilter	过滤器是否生效
	run				生效后执行的业务逻辑

完整代码如下

	@Component
	public class LoginFilter extends ZuulFilter {
	    /**
	     * 选择过滤类型(pre,post,route,error)
	     * @return
	     */
	    @Override
	    public String filterType() {
	        return PRE_TYPE;
	    }

	    /**
	     * 过滤器顺序,越小越先执行
	     * @return
	     */
	    @Override
	    public int filterOrder() {
	        return 4;
	    }

	    /**
	     * 过滤器是否生效
	     * @return
	     */
	    @Override
	    public boolean shouldFilter() {
	        //ACL
	        RequestContext requestContext = RequestContext.getCurrentContext();
	        HttpServletRequest request = requestContext.getRequest();
	        if("/apigateway/order/api/v1/order/save/save".equalsIgnoreCase(request.getRequestURI())){
	            return true;
	        }
	        return false;
	    }

	    /**
	     * 业务逻辑
	     * @return
	     * @throws ZuulException
	     */
	    @Override
	    public Object run() throws ZuulException {
	        //JWT
	        RequestContext requestContext = RequestContext.getCurrentContext();
	        HttpServletRequest request = requestContext.getRequest();
	        String token = request.getHeader("token");
	        if(StringUtils.isBlank(token)){
	            token = request.getParameter("token");
	        }
	        if(StringUtils.isBlank(token)){
	             requestContext.setSendZuulResponse(false);
	             requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
	        }
	        return null;
	    }

4. 细节整理

  1. requestContext

    RequestContext requestContext = RequestContext.getCurrentContext();
    HttpServletRequest request = requestContext.getRequest();

    用来在zuul中获取request对象 requestContext为上下文

  2. 其他

    requestContext.setSendZuulResponse(false); 设置是否继续发送请求到下游服务器,即是否拦截,false为拦截
    requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value()); 可以使用Spring封装好的状态码

五. 高级篇幅之高并发情况下接口限流特技

	使用Google的Guava框架做限流处理
	1. nginx层限流
	2. 网关层限流

1. 原理分析

	在木桶里每秒放一定数量的令牌,表示最大的承载量,有请求进入时一次取一个,如果取完了,说明达到了最大的承载量,则该请求被抛弃,达到限流的目的.

2. 代码编写

	@Component
	public class OrderRateLimiterFilter extends ZuulFilter {

	    //每秒产生1000个令牌
	    private static final RateLimiter RATE_LIMITER = RateLimiter.create(1000);
	    @Override
	    public String filterType() {
	        return PRE_TYPE;
	    }

	    @Override
	    public int filterOrder() {
	        return -4;
	    }

	    @Override
	    public boolean shouldFilter() {
	        RequestContext requestContext = RequestContext.getCurrentContext();
	        HttpServletRequest request = requestContext.getRequest();
	        //只对订单接口做限流
	        if("/apigateway/order/api/v1/order/save/save".equalsIgnoreCase(request.getRequestURI())){
	            return true;
	        }
	        return false;
	    }

	    @Override
	    public Object run() throws ZuulException {
	        RequestContext requestContext = RequestContext.getCurrentContext();
	        if(!RATE_LIMITER.tryAcquire()){
	            requestContext.setSendZuulResponse(false);
	            requestContext.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value());
	        }
	        return null;
	    }
	}

六. Zuul微服务网关集群搭建

  1. nginx + lvs + keepalive


标题:06-微服务网关zuul
作者:mahaonan
地址:https://mahaonan.fun/articles/2022/07/18/1658146999849.html