企业级网关设计

news2024/11/20 16:31:31

tips:本文完全来源于卢泽龙!!!

一、Gateway概述

1.1设计目标

在这里插入图片描述

1.2gateway基本功能

中文文档参考:https://cloud.tencent.com/developer/article/1403887?from=15425
在这里插入图片描述

三大核心:
在这里插入图片描述

二、引入依赖和yaml配置

1.1maven依赖(大坑:spring-web和actuaor一定不要引入!)

<!--gateway-->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos服务发现依赖-->
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
</dependency>

1.2BootStrap.yaml配置

spring:
  application:
    name: rical-gateway
  cloud:
    nacos:
      discovery:
        server-addr: xx.xxx.xx.xx:8848
      config:
        server-addr: xx.xxx.xx.xx:8848 #Nacos作为配置中心地址
        file-extension: yaml #指定yaml格式的配置

1.3动态路由配置rical-gateway-dev.yaml(nacos配置)

spring:
  cloud:
    gateway:
      routes:
        - id: search-movieInfo
          uri: https://www.maoyan.com
          predicates:
            - Path=/films/**
        - id: self-check
          uri: http://localhost:8080
          predicates:
            - Path=/demo/selfCheck.json


rical:
  gateway:
    request:
      qpslimit: 1
      timeout: 0

三、自定义Filter

3.1、gateWay网关扩展点介绍

在这里插入图片描述

使用到gateway过滤器:
在这里插入图片描述

3.2、全局限流器

通过在nacos平台的rical-gateway-dev.yaml配置qpslimit和timeout这两个参数,实现限制qps和限流后的等待时间。遭到限制时,直接给客户端返回error响应!

@Component
@Slf4j
public class LimitFilter implements GlobalFilter, Ordered
{

    @Value("${rical.gateway.request.qpslimit}")
    private Double qpslimit;

    @Value("${rical.gateway.request.timeout}")
    private Integer timeout;

    //创建一个限流器,参数代表每秒生成的令牌数(用户限流频率设置 每秒中限制qpslimit个请求)
    RateLimiter rateLimiter;


    /**
     * 为什么要在bean的初始化方法赋值?
     * 因为@value注解是在spring的 populateBean 方法中 通过 AutowiredAnnotationBeanPostProcessor后置处理器中赋值
     *        * 而如果直接在上面赋值他的执行时机是jvm启动时赋值,该步骤会在spring之前就会产生npe异常
     */
    @PostConstruct
    public void init(){
        rateLimiter = RateLimiter.create(qpslimit);
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpResponse response = exchange.getResponse();
        ServerHttpRequest request = exchange.getRequest();
        HttpHeaders header = response.getHeaders();
        header.add("Content-Type", "application/json; charset=UTF-8");
        RequestPath path = request.getPath();

        //设置等待超时时间的方式获取令牌,如果超timeout为0,则代表非阻塞,获取不到立即返回
        boolean tryAcquire = rateLimiter.tryAcquire(timeout, TimeUnit.SECONDS);
        log.info("com.wtrue.rical.gateway.filter.LimitFilter.filter , tryAcquire = {}",tryAcquire);
        if (!tryAcquire) {
            JSONObject jsonObject = setResultErrorMsg("当前访问用户过多,请稍后重试");
            DataBuffer buffer = response.bufferFactory().wrap(jsonObject.toJSONString().getBytes());
            return response.writeWith(Mono.just(buffer));
        }
        // 放行
        return chain.filter(exchange);
    }

    private JSONObject setResultErrorMsg(String msg) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", "406");
        jsonObject.put("message", msg);
        return jsonObject;
    }


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

3.3、全局日志打印器

注意:该日志打印器只打印配置好路由且没有被上面限流器限流的http请求(比如用户随便乱输入个路径进行请求是不会打印日志的)

@Component
@Slf4j
public class LoggerFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1.获取请求信息
        ServerHttpRequest request = exchange.getRequest();
        InetSocketAddress address = request.getRemoteAddress();
        String method = request.getMethodValue();
        URI uri = request.getURI();
        HttpHeaders requestHeaders = request.getHeaders();
        // 获取请求query
        MultiValueMap<String, String> map = request.getQueryParams();
        log.info("LoggerFilter.filter , request come in, please look down: \n{\n\trequest = {} \n\taddress = {} \n\tmethod = {} \n\turi = {} \n\trequestHeaders = {} \n\tmap = {}\n}",request,address,method,uri,requestHeaders,map);

        // 2.获取响应信息
        ServerHttpResponse response = exchange.getResponse();
        HttpStatus statusCode = response.getStatusCode();
        MultiValueMap<String, ResponseCookie> cookies = response.getCookies();
        HttpHeaders responseHeaders = response.getHeaders();
        log.info("LoggerFilter.filter , response is : \n{\n\tstatusCode = {} \n\tcookies = {} \n\tresponseHeaders = {}\n}",statusCode,cookies,responseHeaders);


        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 1;
    }
}

四、服务测试(类似美团OCTO功能)

1、大体流程图

在这里插入图片描述

2、具体实现方法

2.1gateway的export包提供一个所有业务方都能使用的controller,并通过springBoot自动装配的办法让业务方一引入依赖就能使用
@RestController
@Slf4j
public class SelfCheckController implements BeanFactoryAware {

    /**
     * 业务方引入该export包,就会把业务方自己的appname放进去
     */
    @Value("${spring.application.name}")
    private String appName;

    private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @PostMapping("selfCheck.json")
    public String testInvoke(@RequestBody SelfCheckRequest request) {
        try {
            //1.安全检测
            invokeSafeCheck(request);

            //2.获取目标bean
            Class<?> beanClazz = Class.forName(request.getBeanClazzName());
            Object tartgetBean = getTartgetBean(beanClazz);

            //3.转化参数类型列表
            Class[] parameterTyps = transformParameterTypes(request.getParameterTypes());

            //4.执行
            Method method = beanClazz.getMethod(request.getMethodName(), parameterTyps);
            Object returnValue = method.invoke(tartgetBean, request.getParameters());

            return JSON.toJSONString(returnValue);

        }catch (Exception e){
            log.error("errMsg : {}",e.getMessage(),e);
            return "自检异常:" + e.getMessage();
        }
    }

    /**
     * 转化参数类型列表
     * @param parameterTypes
     * @return
     */
    @SneakyThrows
    private Class[] transformParameterTypes(String[] parameterTypes) {
        if (ArrayUtils.isEmpty(parameterTypes)) {
            return new Class[0];
        }
        Class[] classes = new Class[parameterTypes.length];
        int index = 0;
        for (String parameterType : parameterTypes) {
            Class<?> paramClzz = Class.forName(parameterType);
            classes[index++] = paramClzz;
        }
        return classes;
    }


    /**
     * 获取目标bean
     * @param beanClazz
     * @return
     */
    private Object getTartgetBean(Class<?> beanClazz) {
        Object bean = beanFactory.getBean(beanClazz);
        if (bean ==  null){
            throw new RuntimeException("本服务没有自检所需要的bean");
        }
        return bean;
    }

    /**
     * 执行前的安全检测
     * @param request
     */
    private void invokeSafeCheck(SelfCheckRequest request) {
        String targetAppName = request.getAppName();
        if (!targetAppName.equals(appName)) {
            throw new RuntimeException("自检错误!本服务不是目标服务,请检查appName是否传递错误~");
        }
    }


}
2.2 业务方一定要配置这两个参数,后面有大用
server.servlet.context-path=/demo
spring.application.name=demo

2.3 nacos配置路由规则

- id: self-check
          uri: http://localhost:8080
          predicates:
            - Path=/demo/selfCheck.json

经过这样配置后,用户就能通过网关访问目标服务器的bean方法了,请求案例如下

POST localhost:10001/demo/selfCheck.json
{
    "appName": "demo",
    "beanClazzName": "com.example.demo.service.ITestService",
    "methodName": "getTestMap",
    "parameterTypes": [
        "java.lang.String",
        "java.lang.Integer"
    ],
    "parameters": ["luzelong",999]
}

目标方法的代码如下:

public Map getTestMap(String key, Integer value) {
    HashMap<String, Integer> map = new HashMap<>();
    map.put(key,value);
    log.info("demo!!!!!!");
    return map;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1912216.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

14-52 剑和诗人26 - RAG 和 VectorDB 简介

检索增强生成 (RAG) 和 VectorDB 是自然语言处理 (NLP) 中的两个重要概念&#xff0c;它们正在突破 AI 系统所能实现的界限。 在这篇博文中&#xff0c;我将深入探讨 RAG&#xff0c;探索其工作原理、应用、优势和局限性。 我们还将研究 VectorDB&#xff0c;这是一种专用于向…

【动态规划Ⅵ】背包问题 /// 组合问题

背包问题 什么是背包问题0-1背包问题分数背包完全背包问题重复背包问题 背包问题例题416. 分割等和子集474. 一和零 完全平方数279. 完全平方数322. 零钱兑换 排列与组合组合&#xff0c;无重复&#xff1a;518. 零钱兑换 II排列&#xff0c;可重复&#xff1a;377. 组合总和 Ⅳ…

Commons-Collections篇-CC7链

前言 和CC5反序列化链相似&#xff0c;CC7也是后半条LazyMap执行命令链不变&#xff0c;但是中间过程通过AbstractMap.equals()触发LazyMap.get()方法 环境 我们可以接着使用之前已经搭建好的环境&#xff0c;具体过程可以看CC1分析文章的环境安装部分 Commons-Collections篇…

【Java 的四大引用详解】

首先分别介绍一下这几种引用 强引用&#xff1a; 只要能通过GC ROOT根对象引用链找到就不会被垃圾回收器回收&#xff0c;当所有的GC Root都不通过强引用引用该对象时&#xff0c;才能被垃圾回收器回收。 软引用&#xff08;SoftReference&#xff09;&#xff1a; 当只有软引…

262个地级市-市场潜力指数(do文件+原始文件)

全国262个地级市-市场潜力指数&#xff08;市场潜力计算方法代码数据&#xff09;_市场潜力数据分析资源-CSDN文库 市场潜力指数&#xff1a;洞察未来发展的指南针 市场潜力指数是一个综合性的评估工具&#xff0c;它通过深入分析市场需求、竞争环境、政策支持和技术创新等多个…

LLM应用构建前的非结构化数据处理(一)标准化处理认识数据

1.学习内容 本节次学习内容来自于吴恩达老师的Preprocessing Unstructured Data for LLM Applications课程&#xff0c;因涉及到非结构化数据的相关处理&#xff0c;遂做学习整理。 2.相关环境准备 2.1 建议python版本在3.9版本以上 chromadb0.4.22 langchain0.1.5 langcha…

Redis-Jedis连接池\RedisTemplate\StringRedisTemplate

Redis-Jedis连接池\RedisTemplate\StringRedisTemplate 1. Jedis连接池1.1 通过工具类1.1.1 连接池&#xff1a;JedisConnectionFactory&#xff1a;1.1.2 test&#xff1a;&#xff08;代码其实只有连接池那里改变了&#xff09; 2. SpringDataRedis&#xff08;lettuce&#…

洛谷 数学进制 7.9

P1100 高低位交换 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 代码一 #include<bits/stdc.h> using namespace std; typedef long long ll; #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)const ll N1e510; char a[N];int main() {IOS;ll a;int b[32]…

【分布式系统】ceph部署(命令+截图巨详细版)

目录 一.存储概述 1.单机存储设备 2.单机存储的问题 3.商业存储 4.分布式存储​编辑 4.1.什么是分布式存储 4.2.分布式存储的类型 二.ceph概述 1.ceph优点 2.ceph架构 3.ceph核心组件 4.OSD存储后端 5.ceph数据存储过程 6.ceph版本发行生命周期 7.ceph集群部署 …

用ce修改植物大战僵尸杂交版银币

第一步打开游戏 用ce打开图中进程 第二步 输入你原始银币 点首次搜索 第三步 找到这个地址 把地址拖下来 第四步 双击直接修改下面数值即可 金币 钻石 都和这个方法一样 不一样的是首次搜索可能会有很多地址 我们改变游戏里面的值 然后再次搜索游戏被改变的值即可准确找到地址

降Compose十八掌之『见龙在田』| Modifier

公众号「稀有猿诉」 原文链接 降Compose十八掌之『见龙在田』| Modifier 通过前面的文章我们学会了如何使用元素来构建和填充我们的UI页面&#xff0c;但这只完成了一半&#xff0c;元素还需要装饰&#xff0c;以及进行动画和事件响应&#xff0c;这才能生成完整的UI。这…

遍历请求后端数据引出的数组forEach异步操作的坑

有一个列表数据&#xff0c;每项数据里有一个额外的字段需要去调另外一个接口才能拿到&#xff0c;后端有现有的这2个接口&#xff0c;现在临时需要前端显示出来&#xff0c;所以这里需要前端先去调列表数据的接口拿到列表数据&#xff0c;然后再遍历请求另外一个接口去拿到对应…

C++|异常

目录 一、异常概念 二、异常使用 2.1异常的抛出与捕获 2.2异常的重新抛出 2.3异常安全注意事项 2.4异常规范 三、自定义异常体系 四、C标准库的异常体系 五、异常的优缺点 对于传统的错误处理机制&#xff0c;例如c语言常用的&#xff1a; 1.assert&#xff0c;捕获到…

社区6月月报 | Apache DolphinScheduler重要修复和优化记录

各位热爱Apache DolphinScheduler的小伙伴们&#xff0c;社区6月月报更新啦&#xff01;这里将记录Apache DolphinScheduler社区每月的重要更新&#xff0c;欢迎关注。 月度Merge Stars 感谢以下小伙伴上个月为Apache DolphinScheduler所做的精彩贡献&#xff08;排名不分先后…

过滤器与拦截器区别、应用场景介绍

我们在进行 Web 应用开发时&#xff0c;时常需要对请求进行拦截或处理&#xff0c;故 Spring 为我们提供了过滤器和拦截器来应对这种情况。 那么两者之间有什么不同呢&#xff1f;本文将详细讲解两者的区别和对应的使用场景。 过滤器 过滤器是一种在 Java Web 应用中用于处理…

2024-7-9 Windows NDK,Clion,C4droid 编译环境配置(基础|使用命令编译,非AndroidStudio),小白(记录)友好型教程

2024-7-9 Windows NDK,Clion,C4droid 编译环境配置(基础|使用命令编译),小白友好型 一直想使用NDK编译出lua库,然后进行开发.结果一直不成功,问题Bug出现了一堆(主要还是自己太菜,毕竟咱是编程散修一名>_<) NDK之前一直不会配置(直接用命令配置的那种,非AndroidStudio),一…

nvm下载

nvm下载 1.下载nvm安装包2.安装nvm3.修改settings.txt4.安装成功5.继续配置 下载nvm之前,你最好将你电脑上的node卸载掉,直接在winx中卸载就行 1.下载nvm安装包 https://github.com/coreybutler/nvm-windows/releases 2.安装nvm 3.修改settings.txt root: E:\nvm\install\nv…

哦华为仓颉语言

本来我不太想说的&#xff0c;奈何有不少粉丝提问提到了这语言&#xff0c;目前的情况我不透露太多&#xff0c;看过这课程C实现一门计算机编程语言到手撸虚拟机实战的懂的自然懂。 在互联网领域几乎大部分应用软件运行在X86 LINUX上居多&#xff0c;如果你有问题可以先学习这…

红酒的秘密配方:如何调配出个性化的口感?

在红酒的世界里&#xff0c;每一滴都蕴藏着大自然的秘密和酿酒师的匠心。那些令人陶醉的口感、迷人的色泽和香气&#xff0c;都是经过精心调配和时光酝酿的结果。今天&#xff0c;就让我们一起揭开红酒调配的神秘面纱&#xff0c;探索如何调配出个性化的口感&#xff0c;感受雷…

大语言模型垂直化训练技术与应用

在人工智能领域&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;已经成为推动技术进步的关键力量&#xff0c;垂直化训练技术逐渐成为研究的热点&#xff0c;它使得大模型能够更精准地服务于特定行业和应用场景。本文结合达观数据的分享&#xff0c…