微服务架构--之Gateway(网关)总结

网关处理流程图

在这里插入图片描述

1.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>01-sca</artifactId>
        <groupId>com.jt</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>sca-gateway</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <!--添加gateway依赖:假如依赖下载不下来:
         1)保证网络没有问题(手机网络,公司网络)
         2)保证maven配置正确(maven软件,远程仓库)
         3)本地库(本地库中尽量不要存在同一个资源的多个版本)
         -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <!--拓展:基于如下依赖中的API可以实现对象与json字符串之间转换-->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.5</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

    </dependencies>

</project>

2.核心配置文件

server:
  port: 9000
spring:
  application:
    name: sca-gateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8180
        #port: 8719
      eager: true  #服务启动时会会向sentinel控制台发送心跳,为我们的应用创建菜单
    gateway:  # API Gateway (负责API管理)
      discovery:
        locator:
          enabled: true  #开启基于服务名获取服务实例的功能(基于服务名创建路由)
      routes: #网关路由配置
         - id: router01  #http://localhost:9000/nacos/provider/echo/hello
           #uri: http://localhost:8081
           uri: lb://sca-provider  #lb表示负载均衡,底层默认使用ribbon实现
           predicates: #定义请求规则(请求需要按照此规则设计)
             - Path=/nacos/provider/echo/** #请求路径设计
             #- After=2021-08-23T13:59:59.789+08:00[Asia/Shanghai]
             #- Header=X-Request-Id, \d+  #\d+表示任何一个数字
             #- Method=GET
             #- Query=pageSize,\d+
           filters:
             - StripPrefix=1 #转发之前去掉path中第一层路径,例如nacos
             #- AddRequestHeader=X-Request-Foo, Bar
             #- AddRequestParameter=foo, hello

#自己定义白名单路径
white:
  prefix: /nacos


# 假如希望调整负载均衡算法,可参考如下配置方式
sca-provider: #这个名字为指定的服务名
  ribbon:
    #NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
  1. id,路由标识符,区别于其他 Route。
  2. uri,路由指向的目的地 uri,即客户端请求最终被转发到的微服务。
  3. predicate,断言(谓词)的作用是进行条件判断,只有断言都返回真,才会执行路由。
  4. filter,过滤器用于修改请求和响应信息。

3.断言(Predicate)分析 

3.1请求时间判断

此类型的断言根据时间做判断,主要有三个:

1) AfterRoutePredicateFactory:判断请求日期是否晚于指定日期
2) BeforeRoutePredicateFactory:判断请求日期是否早于指定日期
3) BetweenRoutePredicateFactory:判断请求日期是否在指定时间段内

-After=2020-12-31T23:59:59.789+08:00[Asia/Shanghai]

当且仅当请求时的时间After配置的时间时,才转发该请求,若请求时的时间不是After配置的时间时,则会返回404 not found。时间值可通过ZonedDateTime.now()获取.

 3.2请求头判断

判断请求Header是否具有给定名称且值与正则表达式匹配。例如:

-Header=X-Request-Id, \d+

3.3请求方式判断

MethodRoutePredicateFactory接收一个参数,判断请求类型是否跟指定的类型匹配。例如:

-Method=GET

3.4请求参数判断

接收两个参数,请求param和正则表达式, 判断请求参数是否具 有给定名称且值与正则表达式匹配。例如:

-Query=pageSize,\d+

4.过滤器(Filter)增强分析

过滤器(Filter)就是在请求传递过程中,对请求和响应做一个处理。Gateway 的Filter从作用范围可分为两种:GatewayFilter与GlobalFilter。其中: 

GatewayFilter:应用到单个路由或者一个分组的路由上。
GlobalFilter:应用到所有的路由上

局部过滤器实现(配置文件中的filters) 

基于AddRequestHeaderGatewayFilterFactory,为原始请求添加Header。 

spring:
  cloud:
    gateway:
      routes:
        - id: add_request_header_route
          uri: https://example.org
          filters:
            - AddRequestHeader=X-Request-Foo, Bar

基于AddRequestParameterGatewayFilterFactory,为原始请求添加请求参数及值,  

spring:
  cloud:
    gateway:
      routes:
        - id: add_request_parameter_route
          uri: https://example.org
          filters:
            - AddRequestParameter=foo, bar

 基于PrefixPathGatewayFilterFactory,为原始的请求路径添加一个前缀路径 

spring:
  cloud:
    gateway:
      routes:
        - id: prefixpath_route
          uri: https://example.org
          filters:
            - PrefixPath=/mypath

 基于RequestSizeGatewayFilterFactory,设置允许接收最大请求包的大小 

spring:
  cloud:
    gateway:
      routes:
        - id: request_size_route
      uri: http://localhost:8080/upload
      predicates:
        - Path=/upload
      filters:
        - name: RequestSize
          args:
            # 单位为字节
            maxSize: 5000000

 全局过滤器设计及实现 

 设置访问的黑白名单:

package com.jt.config;

import com.google.gson.Gson;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.Map;

/**
 * 自定义的全局过滤器,作用域所有路由
 */
@Component
public class AuthGatewayFilter implements GlobalFilter, Ordered {

        @Value("${white.prefix}")
        private String whitePrefix;
    /**你的业务可以写到这个filter方法内部
     * @param exchange 基于此对象可以获取请求和响应对象
     * @param chain 这个对象指向了一个过滤链(这个链中有多个过滤器)
     * */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange,
                             GatewayFilterChain chain) {
        //1.获取请求对象
        ServerHttpRequest request = exchange.getRequest();
        //2.获取请求数据
        String path = request.getURI().getPath();
        System.out.println("path="+path);
        //String username=request.getQueryParams().getFirst("username");
        //3.对请求数据进行处理
        //例如判定请求的path是否在我们允许的范围之内
        System.out.println("whitePrefix="+whitePrefix);
        if(!path.startsWith(whitePrefix)) {//判断路径的前缀
            //获取响应对象
            ServerHttpResponse response = exchange.getResponse();
            //设置响应状态码,这里的值为502
            //response.setStatusCode(HttpStatus.BAD_GATEWAY);
            //结束当前请求
            //return response.setComplete();//直接结束
            //假如希望响应一些具体内容到客户端
            //String content="request failure";
            //byte[] bytes=content.getBytes();
            Map<String,Object> map=new HashMap<>();
            map.put("message","request failure");
            map.put("status",502);
            //将map对象转换为json字符串?
            //String jsonStr="{\"message\":\"request failure\",\"status\":502}";
            Gson gson=new Gson();
             String jsonStr=gson.toJson(map);//将map对象转换json格式字符串.
            byte[] bytes=jsonStr.getBytes();
            DataBuffer dataBuffer=
                    response.bufferFactory().wrap(bytes);
            return response.writeWith(Mono.just(dataBuffer));
            //Spring WebFlux,Mono是一个可以封装0个或1个元素的序列对象.
        }
        //4.返回响应结果
        return chain.filter(exchange);//将请求交给下一个过滤器进行处理
    }
    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}

5.限流设计及实现

网关是所有请求的公共入口,所以可以在网关进行限流,而且限流的方式也很多,我们采用Sentinel组件来实现网关的限流。Sentinel支持对SpringCloud Gateway、Zuul等主流网关进行限流。参考网址如下:

https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel 

启动网关项目,检测sentinel控制台的网关菜单。
启动时,添加sentinel的jvm参数,通过此菜单可以让网关服务在sentinel控制台显示不一样的菜单,代码如下。

-Dcsp.sentinel.app.type=1  

在这里插入图片描述         基于请求属性限流

基于请求属性限流

在这里插入图片描述

        自定义API维度限流(重点)

新建api分组

在这里插入图片描述 

新建分组流控规则,如图所示:

在这里插入图片描述

定制流控网关返回值

package com.jt.config;

import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.fastjson.JSON;
import com.google.gson.Gson;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class GatewayConfig {
    public GatewayConfig(){
        GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() {
            @Override
            public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
                ServerHttpResponse response = serverWebExchange.getResponse();
                Map<String,Object> map=new HashMap<>();
                map.put("state",429);
                map.put("message","two many request");
                //String jsonStr= JSON.toJSONString(map);
                Gson gson = new Gson();
                String s = gson.toJson(map);
                return ServerResponse.ok().body(Mono.just(s), String.class);
            }
        });
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值