微服务网关zuul

网关简介

在这里插入图片描述
有的服务不需要登录,如商品服务,不需要登录也可以浏览,有的服务需要登录,如下单服务;前端请求来了之后,被网关拦截,网关判断这些地址需不需要登录,不需要的话放行,需要的话跳转到登录服务
在这里插入图片描述
在这里插入图片描述

zuul组件的基本使用

网关是单独的一个项目,所以需要新建api-gateway网关项目
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
上边新建项目的时候已经把zuul需要的依赖加进去了,不需要手动添加依赖了:

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

配置文件:

server:
  port: 9000


#服务名称
spring:
  application:
    name: api-gateway

#指定注册中心地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

在启动类里新增注解@EnableZuulProxy

@SpringBootApplication
//代理服务器---网关
@EnableZuulProxy
public class ApiGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(ApiGatewayApplication.class, args);
    }
}

访问规则:

 http://gateway:port/service-id/***

例如之前的下单路径:

http://localhost:8781/api/v1/order/save?product_id=6&user_id=4

使用网关后的访问路径:

http://localhost:9000/order-service/api/v1/order/save?product_id=6&user_id=4

也可以在配置文件里自定义上边的"order-service":

#自定义服务名字(自定义路由映射)
zuul:
  routes:
    order-service: /apigateway/**

此时访问路径可以是下边这种的(两种都可以使用):

http://localhost:9000/apigateway/api/v1/order/save?product_id=6&user_id=4

环境隔离配置——将第一种访问方式禁用掉:

zuul:
  routes:
    order-service: /apigateway/**
    #禁用order-service,使其不能对外提供服务
  ignored-services: order-service

此时,下边这种方式就访问不了了:

http://localhost:9000/order-service/api/v1/order/save?product_id=6&user_id=4

对外禁用所有以"-service"结尾的服务:

zuul:
  routes:
    order-service: /apigateway/**
  #ignored-services: order-service
  #对外禁用-service结尾的服务
  ignored-patterns: /*-service/**

即最后配置文件:

#自定义服务名字(自定义路由映射)
zuul:
  routes:
    #以后order-service与product-service这种方式不能访问了,统一入口为apigateway,下边这两个地址一样,这样是不可以的,后边讲
    order-service: /apigateway/**
    product-service: /apigateway/**
  #ignored-services: order-service
  #对外禁用-service结尾的服务
  ignored-patterns: /*-service/**

这样起到了内外网隔离的作用,原理图如下:
在这里插入图片描述

zuul常用问题分析

1、多个服务的网关地址不能完全一样

#自定义服务名字(自定义路由映射)
zuul:
  routes:
    #注意下边的多个网关地址不能完全一样,不然后边的会覆盖前边的
    order-service: /apigateway/order/**
    product-service: /apigateway/product/**
  #ignored-services: order-service
  #对外禁用-service结尾的服务
  ignored-patterns: /*-service/**

2、http请求头过滤问题
下单服务里模拟获取tooken与cookie
在这里插入图片描述
postMan发送请求(在请求头加上tooken与cookie):
在这里插入图片描述
后台没有获取到cookie:
在这里插入图片描述

源码:这三项请求头都被过滤了
在这里插入图片描述
这是因为cookie被zuul网关过滤掉了,解决:sensitive-headers置空即可

#自定义服务名字(自定义路由映射)
zuul:
  routes:
    #以后order-service与product-service这种方式不能访问了,统一入口为apigateway,
    order-service: /apigateway/order/**
    product-service: /apigateway/product/**
  #ignored-services: order-service
  #对外禁用-service结尾的服务
  ignored-patterns: /*-service/**
  #解决获取不到cookie的问题(这里置空,表明不过滤任何请求头)
  sensitive-headers: 

zuul流程:
在这里插入图片描述

自定义zuul过滤器实现登录鉴权实战

1、新建filter包
2、新建类继承ZuulFilter,重写方法
3、在类顶部加注解@Comment让spring扫描

package com.maltose.apigateway.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.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;

/**
 * @Author: sgw
 * @Date 2019/4/7
 * @Description:登录过滤器
 **/
@Component
public class LoginFilter extends ZuulFilter {
    /**
     * 过滤器类型:前置过滤器
     *
     * @return
     */
    @Override
    public String filterType() {
        //PRE:代表前置类型的过滤器
        return PRE_TYPE;
    }

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

    /**
     * 过滤器是否生效:true--生效
     *
     * @return
     */
    @Override
    public boolean shouldFilter() {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        //  /apigateway/product/api/v1/order/save
        System.out.println("URI:" + request.getRequestURI());
        //http://localhost:9000/apigateway/product/api/v1/order/save
        //System.out.println("URL:" + request.getRequestURL());
        //只拦截这个下单接口(需要登录),常量放前边的话不会报空指针异常,request.getRequestURI()放前边的话容易报空指针
        /**
         * 如果服务多的话,可以搜索ACL,把服务地址放redis缓存里,这里就不用把地址写死了
         * 服务少的话可以像下边这种使用多个if进行判断
         */
        if("/apigateway/order/api/v1/order/save".equalsIgnoreCase(request.getRequestURI())){
            //返回true说明拦截了,则下一步进入run方法
           return true;
        }
        //返回false1的话直接放行,不拦截
        return false;
    }

    /**
     * 过滤逻辑
     *
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
        System.out.println("拦截了");
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        String token = request.getHeader("token");

        if(StringUtils.isBlank(token)){
            //有时候在headr里找不到,可以在参数里获取到
            token=request.getParameter("token");
        }
        //登录校验逻辑,根据公司情况自定义,
        // 通过加密算法把token加密后返回给用户,用户来来的时候拿着加密后的token过来,我们在这里判断这个token是否有效--JWT技术
        if(StringUtils.isBlank(token)){
            //没有token值,说明没登录,不继续向下走
            requestContext.setSendZuulResponse(false);
            //设置返回状态码,这里的值是401(未授权)
            requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        }

        return null;
    }
}

高并发下接口限流技术gauva(谷歌的框架)

MySql最大连接数3000;
在这里插入图片描述
原理:框架每秒向桶里放100个令牌,接口请求来了先去拿令牌,拿到令牌后才能继续向后走,否则不允许向后执行;当接口请求太频繁的话就会拿不上令牌,此时就起到了限流的作用;
我们在网关层做一个限流:

package com.maltose.apigateway.filter;

import com.google.common.util.concurrent.RateLimiter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.http.HttpStatus;

import javax.servlet.http.HttpServletRequest;

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;

/**
 * @Author: sgw
 * @Date 2019/4/7 20:25
 * @Description: 订单接口限流
 **/
public class OrderRateLimiterFilter extends ZuulFilter {
    //使用google框架gauva,每秒产生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".equalsIgnoreCase(request.getRequestURI())) {
            //返回true说明拦截了,则下一步进入run方法
            return true;
        }
        return false;
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        //RATE_LIMITER.tryAcquire()表示立马去拿令牌,只要拿不到就拦截;也可以设置一段时间内拿不到再拦截
        if (!RATE_LIMITER.tryAcquire()) {
            requestContext.setSendZuulResponse(false);
            //状态码429:太多请求的错误
            requestContext.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value());
        }
        return null;
    }
}

zuul微服务网关集群搭建

目前网关只有一个,局域网内的服务可能是集群搭建,但是网关挂了就都废了
在这里插入图片描述
所以网关也要做集群部署
在这里插入图片描述
IDEA模拟集群搭建
在这里插入图片描述
分布式链路追踪系统

发布了46 篇原创文章 · 获赞 12 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_33417321/article/details/88958616