API 开放平台项目(已整理,已废弃)

项目大纲

API 开放平台项目(已整理,已废弃)_第1张图片

前端

  • React 18
  • Ant Design Pro 5.x 脚手架
  • Ant Design & Procomponents 组件库
  • Umi 4 前端框架
  • OpenAPI 前端代码生成

后端

  • Java Spring Boot
  • MySQL 数据库
  • MyBatis-Plus 及 MyBatis X 自动生成
  • API 签名认证(Http 调用)
  • Spring Boot Starter(SDK 开发)
  • Dubbo 分布式(RPC、Nacos)
  • Swagger + Knife4j 接口文档生成
  • Spring Cloud Gateway 微服务网关
  • Hutool、Apache Common Utils、Gson 等工具库
  1. 项目介绍和计划
  2. 需求分析
  3. 业务流程和子系统介绍
  4. 技术选型(各技术作用讲解)
  5. 前后端项目初始化
    1. 前端 Ant Design Pro 框架最新版本教程
    2. 后端 Spring Boot 万用模板使用
  6. 数据库表设计
  7. 前后端代码自动生成(强烈推荐,大幅提高开发效率!)
  8. 登录页开发
  9. 接口管理功能开发(Ant Design 高级组件使用)
  10. 模拟 API 接口项目开发
  11. HTTP 接口调用
  12. API 签名认证详解及开发
  13. 客户端 SDK 开发(Spring Boot Starter)
  14. 管理员接口发布 / 下线功能开发
  15. 接口列表页开发
  16. 在线调试接口功能开发
  17. 接口调用统计开发
    1. 后端开发
    2. 优化方案分析及对比
  18. API 网关详解
    1. 网关介绍及优点
    2. 10 种网关应用场景
    3. 网关分类及技术选型
  19. Spring Cloud Gateway 网关实现
    1. 详细带读官方文档
    2. 统一业务处理:用户鉴权及接口调用次数统计
  20. 项目分布式改造
    1. 公共模块抽象
    2. RPC 和 HTTP 调用详解及对比
    3. Dubbo 框架讲解及示例项目开发
    4. Dubbo 业务实战
  21. 管理员统计分析功能
    1. 前端 2 种可视化库的使用
    2. 后端聚合查询接口开发
  22. 项目扩展点及上线分析

一、初始化前后端框架

项目前端初始化---脚手架安装

直接使用开始使用 - Ant Design Pro,按照他的步骤安装即可。

1、安装库(电脑安装一次即可)

(base) wangjia@wangbangjia ~ % sudo npm i @ant-design/pro-cli -g

2、在指定目录创建项目框架

(base) wangjia@wangbangjia 星球项目 % pro create yuapi-frontend          
?  使用 umi@4 还是 umi@3 ? umi@4
全量区块暂时不支持 umi@4

3、安装依赖:yarn install安装package.json对应的依赖-----node_modules时,一定要在项目根目录!!!!

即可得到前端框架了

注意版本号控制

切换nodeMac下的nodeJs版本切换和升级_mac npm版本切换_-HaiXin的博客-CSDN博客

 yarn版本控制yarn卸载与版本降级升级_yarn降级_votaries的博客-CSDN博客

注意还要使用yarn安装所有的依赖--缺少啥依赖就会报错--再安装也行

直接敲 yarn 安装依赖

这个依赖还是很重要的!

sudo yarn add eslint-plugin-unicorn --dev

前端与后台服务交互

    大致流程:
        1.UI 组件交互操作;
        2.调用 model 的 effect;
        3.调用统一管理的 service 请求函数;
        4.使用封装的 request.js 发送请求;
        5.获取服务端返回;
        6.然后调用 reducer 改变 state;
        7.更新 model。
 

2、项目后端初始化--

使用springboot-init框架就好了。

启动之前要application.yml配置Redis、数据库的连接信息。之后MySQL连接IDEA,

二、正式业务

  • 第一期 -- 初始化和展示
  1. 项目设计、技术选型
  2. 基础项目的搭建
  3. 接口管理
  4. 用户查看接口

1、数据库表设计

        --- 建立接口信息表

使用http://sqlfather.yupi.icu/   根据字段生成sql语句

*后端生成SQL表的 CRUD

        ---MybatisX-generator

MyBatisX Generator 可以根据数据库表结构信息快速生成与数据库交互所需的

实体类Mapper 接口XML 映射文件等代码

API 开放平台项目(已整理,已废弃)_第2张图片

API 开放平台项目(已整理,已废弃)_第3张图片

API 开放平台项目(已整理,已废弃)_第4张图片

第三幅图本地还会有module也要勾选

最终生成的generator目录结构

API 开放平台项目(已整理,已废弃)_第5张图片

将每个文件粘贴复制到对应的目录中 删掉generator即可

API 开放平台项目(已整理,已废弃)_第6张图片

后端增删改查 -- 调用现有代码完成。

*前端生成后端接口CRUD

前端:实现登录功能 + 接口信息增删改查

        怎么让前端调用后台的接口,去实现接口信息的增删改查管理?

前端接口调用:oneapi插件自动生成 -- 使用openapi规范

已经有了后端,想要前端直接生成调用后端的代码,只需要将后端基于openapi的文档提供给前端即可

获取后端openapi的JSON文档:后端主页的分组URL连在ip:port/工程名/后面即可

例如后端主页地址http://localhost:7529/api/doc.html#/home

查看到分组URL为/v3/api-docs  所以

最终后端基于openapi的文档地址为http://localhost:7529/api/v3/api-docs

将config/config.ts中openAPI 对应的path改为http://localhost:7529/api/v3/api-docs并设置项目名

然后package.json运行openapi即可生成前端增删改查 调用后端的接口 在service/yuapi-backend中6个文件

看不懂,先熟悉一下。

然后跟着做完成测试。

测试:使用真实的后端接口,就要使用dev方式运行。

用户中心项目copy以下注册页面代码

成功使用后端数据生成接口信息,让前端调用 以用户身份登录成功。

第一节即将结束。先步道乐跑打卡吃饭,最近一段时间,又开始起飞。

** 问题解决

为啥刷新页面,就需要重新登陆?

--- 1、前端没有种上Cookie

---2、前端发请求没有带上Cookie  

        在requestConfig.ts 发送请求配置中添加withCredentials: true

        (用于指定跨域请求时是否发送身份凭证(如 cookies、HTTP 认证等))

权限管理:

只有管理员可以操作的接口信息管理

service/access.ts为权限管理判断

还可以直接对数据库操作,设置其userRole 是user还是admin

API 开放平台项目(已整理,已废弃)_第7张图片

管理员页面填充接口信息

TableList的index.ts的columns变量中改为自己需要展示的列,然后修改request的方法

无登录2;39;40

由于之前没有刚开始就删除国际化配置,之后再执行的,导致出现故障,现在登录界面无法加载,也就是权限校验没法执行,技术解决不了,趁着还没有进行太多,直接重新,从头来过。

  • 第二期 -- 接口调用
  1. 继续开发接口管理前端页面
  2. 开发模拟api接口
  3. 开发调用这个接口的代码
  4. 保证调用的安全性 (api签名认证)
  5. 客户端SDK开发
  6. 管理员接口 发布 与调用
  7. 接口文档展示、接口在线调用

注意:Ant-design Pro给出的框架,什么增删改查就是个模板,根本上还是要自己调用,或者进行修改。

1、完成了第二期接口管理前端页面 -- pages/InterfaceInfo

对于表单的处理,最重要的就是定义好columns,其余要考虑的就是调用组件完成添加、删除、修改即可。

2、开发模拟API接口 -- yuapi-interface

也就是写一个能发送请求并响应的springboot小项目

3、调用接口

几种http调用方式

HttpClient、RestTemplate、第三方库(Hutool,OKHTTP)

使用Hutool

4、API签名认证

本质: 1、签发签名  2、使用签名(校验签名)

Cookie是第一次使用要权限校验,之后会保存在浏览器中,每次发请求登录就会将用户信息加在请求报文中,实现“无校验登录”

但是由于调用API用户资格无法得知,每一次调用API都要进行一次权限认证。

通过Http request Header传递参数

参数1、accessKey:调用的表示 userA、userB

参数2、secretKey:秘钥   --- 该参数不放到请求头中传递,用于生成签名

类似用户名和密码(区别:ak、sk无状态的)

不可将秘钥直接在服务器间传递,有可能被拦截。

加密方式:对称加密、非对称加密、MD5签名(不可解密)

参数3、用户请求参数

MD5加密:

参数4、sign参数

用户参数 + 秘钥 => 签名生成算法得到值(不可解密)  (比如:yupi + abcdefgh = diaehufishroser)

服务器校验方法:

服务器用相同的参数和算法来生成签名,再与用户传的进行校验。

怎么放重放? (例如配置了代理,代理拦截获取签名,直接重放后发送)

参数5、加nonce随机数,只能用一次(服务端要保存已使用过的随机数)

参数6、加timestamp时间戳,检验时间戳是否过期

现在正在做的就是 按照6个参数  完成API签名认证 (客户端制作签名、服务端认证签名)

客户端咋做? :根据参数 + 加密算法 ==》 生成签名   在发送请求时,将签名放在请求头中。

使用Hutool工具发送http请求,获取相应数据、打印。

服务端咋做? :根据发送请求的URL映射到具体的API(方法),完成签名校验,返回响应数据。

API签名认证很灵活,采用什么签名算法只是一个选择问题。最重要的就是选择哪些参数用来生成最终的API签名要根据具体场景来选择。(比如userId、appid、固定值等)

思考:难道开发者每次调用接口都要写一遍签名算法?

开发一个简单易用的SDK

理想情况:开发者只需要关注调用哪些接口,传递什么参数,就像调用自己的代码一样。

开发starter好处:开发者引入之后,可以在applocation.yml中写配置,自动创建客户端。

spring-boot-configuration-processor作用是自动生成配置的代码提示

建立加分项 --- 写starter:

首先就是确定包含那些依赖;其次在Resources中写文件夹META-INF的spring.factories中指定配置的注册类xxxClientConfig,在注册类中通过注解@ConfigurationProperties("yuapi.client")读取到配置类信息

使用sdk,咋就创建bean失败了,改了好久,最基本的spring创建bean到地了。先不改了,之后还会有延伸,到时再改

第三期

  1. 开发接口发布/下线的功能(管理员)
  2. 前端去浏览接口、查看接口文档、申请签名(注册)
  3. 在线调试(用户)
  4. 统计用户调用接口的次数
  5. 优化系统-API网关

1、开发接口发布/下线的功能(管理员)

发布接口(仅管理员):
1、校验该接口是否存在
2、判断该接口是否可调用
3、修改接口数据库中的状态字段为1

todo 判断该接口是否可以调用时 由固定方法名 改为 根据测试地址来调用
下线接口(仅管理员):
1、校验该接口是否存在
2、修改接口数据库中的状态字段为0

在controller层 写发布与下线接口

controller 层写上线,下线接口就还可以,但是引入YuApiClient就不行了,显示是无法生产bean,刚写的是没问题的,直接用yupi的也是出现这个问题,继续找找吧,肯定是个小问题,找不到,就继续看视频,晚上再找。

依然还是没有找到,只用不用注入的bean就行,这个问题很奇怪,我在注入的时候,都还有提示,自动导入jdk,也都不报错,但是要用到实例的bean就报错了。

晚上准备API签名认证  API网关的代码讲解录制发布到B站上 

一来是再次梳理一遍、二来就是以便后来项目复习快速回忆

刚刚在InterfaceInfoController中补充写了接口的操作函数--后端发布 & 下线的接口,但是前端仅仅是显示,咋进行调用?

        前端不用写任何关于接口调用的方法,直接使用openapi生成

后端改了,想要前端进行调用,直接使用openapi生成一下

1、做了主页展示接口并实现调用 --- pages/Index 加载展示接口列表(√)

2、查看文档接口页面 --- pages/InterfaceInfo中展示 单个接口信息(√)

3、实现用户注册时生成签名  在UserServiceImpl在插入数据前 生成ak、sk 然后插入。(√)

由于后端初始化项目User内没有ak、sk字段,还要在实体以及对应的mapper中添加字段

现在出现的最大的问题就是  使用openapi根据后端代码自动生成前端调用后端的接口 生成的不全!!到底是后端缺少了啥,还是openapi生成出现了问题?

不是少一俩个函数,实体也都少了,不解决没法进行。有些函数之前写也还有啊,怎么就没了?

标准json数据格式:

[
  {
    "name": "username", "type": "string"
  }
]

注意调用逻辑:前端 -> 后端 -> 接口服务

                然后    接口服务 -> 后端 -> 前端

第四期

1、开发接口调用次数的统计
2、优化整个系统的架构(API网关)
  网关是啥?啥作用?应用场景及实现?结合业务去应用网关。

todo 调用接口测试失败,显示是json格式不匹配 下午解决---原来是自己id赋值没有把对象中的id数值取出来,导致直接把对象赋值给了id。

1、用户接口信息表 建表,使用MybatisX-Generator生成对应的三层代码文件,分别移动后,并对dao层实体-mapper、Service层方法、controller层增删改查 所有代码基本处理(√)

2、

统计每个接口的调用次数,是针对每个接口都写一下统计的方法?大量重复工作!
使用AOP优点:独立于接口,在每个接口调用之后统计次数+1
缺点:只存在于单个项目中,如果每个团队都要开发自己的模拟接口,那么都要写一个切面,仍然大量重复工作。

终极解决方案:网关

文档:Spring Cloud Gateway 中文文档

API 开放平台项目(已整理,已废弃)_第8张图片

*API网关:

关键点:根据断言的路由及局部的过滤器yml配置;全局过滤器鉴权、签名认证、调用次数校验及+1等功能实现。

定义 :API网关是一种集成了配置发布、环境管理、接入认证,用户鉴权、访问控制等功能的                       API管理和服务治理的工具。

使用API网关托管API,即可高效,安全、低成本的管理服务。API网关作为请求的单一入口点,将请求分配给相应的服务,然后收集结果并将其传递给请求者。而不是让客户单独请求访问每项微服务。

API 开放平台项目(已整理,已废弃)_第9张图片

  1. 核心功能:路由、鉴权
  2. 管理上处理:负载均衡、跨域、业务处理、访问控制、发布控制、流量染色、接口保护
  3. 日志上处理:监控日志、报表
路由:
    起到转发的作用。比如有接口A和接口B,网关会记录这些信息,根据用户访问的地址和参数,转发请求到对应的接口。(服务器/集群)
    /a -> 接口A
    /b -> 接口B
负载均衡:
    路由的基础上
    /c -> 服务A / 集群A(随机转发到其中的某一个机器)
统一鉴权:
    判断用户是否具有权限进行操作。无论访问什么接口,都统一去判断权限,不用重复写。
统一处理跨域:
    网关统一处理跨域,不在每个项目单独处理
统一业务处理:
    把一些每个项目中都要做的通用的逻辑放到上层(网关),统一处理,比如本项目的次数统计
访问控制:
    黑白名单,比如限制DDOS ip
发布控制:
    灰度发布,比如上线新接口,先给新接口分配20%流量,老接口80%,再慢慢调整比重
流量染色:
    给请求(流量)添加一些标识,一般是设置请求头中,添加新的请求头

统一接口保护:限制请求、信息脱敏、降级(熔断)、限流、超时时间

统一日志:
    统一的请求、相应信息记录
统一文档:
    将下游项目的文档进行整合,在一个页面统一查看

网关的分类:
    全局网关(接入层网关):作用是负载均衡
    业务网关(微服务网关):会有一些业务逻辑,作用是将请求转发到不同的业务、项目、接口、服务。


实现
    1、Nginx(全局网关)、Kong网关(API网关)编程成本高
    2、Spring Cloud Gateway 性能高、可以用java代码写逻辑 
建议开启日志
logging:
  level:
    org:
      springframework:
        cloud:
          gateway: trace

核心概念
    路由:根据什么条件
    断言:一组规则、条件,用来确定如何转发路由
    过滤器:对请求进行一系列的处理,比如添加请求头、添加请求参数


请求流程:
    1、客户端发起请求
    2、Handle Mapping:根据断言,去将请求转发到对应的路由
    3、Web Handle:处理请求(一层层经过过滤器)
    4、实际调用服务

俩种配置方式
    1、配置式(方便、规范)
    2、编程式(灵活)


断言
      (作用:根据断言转发路由)
     1、After在XX时间之后
     2、Before在XX时间之前
     3、Between在XX时间之间
     4、请求类别
     5、请求头(包含Cookie)
     6、权重
     7、查询参数
     8、客户端地址

过滤器
     (基本功能:对请求头、请求参数、响应头的增删改查)
     1、添加请求头
     2、添加请求参数
     3、添加响应头
     4、降级(设置备份地址)

鱼皮经验:

基础核心知识掌握了,其他的应用类的知识,晓得是什么,应用场景就行了,不会就直接查文档。

第五期
   1、实现统一的用户鉴权、统一的接口调用次数统计(把API网关应用到项目中)
   2、完善功能

  业务逻辑

 
      1、用户发送请求到API网关
      2、请求日志
      3、(黑白名单)
      4、用户鉴权(判断ak、sk是否合法)
      5、请求的模拟接口是否存在
      6、请求转发,调用模拟接口
      7、响应日志
      8、调用成功,接口调用次数 + 1
      9、调用失败,返回一个规范的错误码

* 具体实现
*       1、请求转发
*          使用前缀匹配断言:所有路径为/api/**的请求进行转发,转发到http://localhost:8123/api/**
*          比如请求网关:http://localhost:8090/api/name/get?name=yupi
*          转发到: http://localhost:8123/api/name/get?name=yupi
*  spring:
*   cloud:
*     gateway:
*       routes:
*         - id: yuapi_route
*           uri: http://localhost:8123
*           predicates:
*             - Path=/api/** 

现在是分布式项目,但是没有引入微服务,微服务啥子? 

*签名认证ak-sk:

本质:1、签发签名  2、校验签名

关键点:生成签名工具

后台生成签名工具 & 网关重新生成进行比对校验

ak-sk 机制基础:

1、ak-sk 由用户注册时提供的用户名产生,并作为用户信息的一部分存储在用户信息表中;

2、accessKey被视为公钥,用于标识用户的身份;secretKey 则被视为私钥,用于加密签名;

accessKey是身份标识,根据请求者accessKey在数据库中拿到对应的有资格用户User,并拿到对应的secretKey,和请求者的body现场生成serverSign
 请求者在发送请求时就会调用签名生成工具生成签名sign,存储在请求头中,拿出来。
  将sign与serverSign对比。
 ak-sk机制:
 请求者根据ak-sk已经生成了签名sign(请求体+秘钥),在发送请求时,将ak和sign一起放在请求头中,
 API网关拿到请求头中的ak与sign,根据ak去数据库确定是哪个用户,拿到对应的sk,重新现场生成serverSign,再完成签名校验。

                                        后台签名工具

存储生成密钥参数的hashmap

//    存储秘钥,放在请求头中
     private Map getHeaderMap(String body){
         Map hashMap = new HashMap<>();
         hashMap.put("accessKey",accessKey);
//         秘钥一定不能发送给后端
         hashMap.put("nonce", RandomUtil.randomNumbers(4));
         hashMap.put("body",body);
         hashMap.put("timestamp",String.valueOf(System.currentTimeMillis() / 1000));
                //使用签名工具生成 签名
         hashMap.put("sign",genSign(body,secretKey));
         return hashMap;
     }

生成签名工具:

public class SignUtils {
    public static String genSign(String body, String secretKey){
        // 创建 SHA256算法 的消息摘要器
        Digester md5 = new Digester(DigestAlgorithm.SHA256);
        // 将请求体和密钥拼接起来以生成待签名的内容
        String content = body + "." + secretKey;
        // 使用消息摘要器计算内容的哈希值,并以十六进制形式返回
        return md5.digestHex(content);
    }
}

将签名封装到请求头中完成发送请求

public String getUserNameByPost(User user){
         String json = JSONUtil.toJsonStr(user);
         HttpResponse httpResponse = HttpRequest.post("http://localhost:8123/api/name/user/")
                 .addHeaders(getHeaderMap(json))
                 .body(json)
                 .execute();
         System.out.println(httpResponse.getStatus());
         String result = httpResponse.body();
         System.out.println(result);
         return result;
     }
}

API网关用户鉴权

1、获取请求头中的accessKey
        HttpHeaders headers = request.getHeaders();
        String accessKey = headers.getFirst("accessKey");
2、根据accessKey获取到对应的调用者
        User invokeUser = innerUserService.getInvokeUser(accessKey);   
3、获取到接口调用者的secretKey 
        String secretKey = invokeUser.getAccessKey(); 
4、根据body内参数与secretKey生成服务端的签名
        String serverSign = SignUtils.genSign(body,secretKey); 
5、将服务端现场生成的签名和请求头中的签名进行对比
        if(sign == null || !sign.equals(serverSign)){ 
        return  handleNoAuth(response); 
        }
 
  

现在是API网关内部的签名认证错误!!!就是sign与serversign不同!!!真是出鬼了!!!到底是哪里出了问题??? --原来是写错了,手欠,排查了好久.

*项目架构 --调用接口流程:

API 开放平台项目(已整理,已废弃)_第10张图片

  • 平台管理员
    • 上线接口:管理员可以将开发完成的接口上线,使其可供接口使用者调用。
    • 下线接口:管理员可以将某个接口下线,即停止该接口的调用。
    • 管理接口:
      • 增:管理员可以添加新的接口到平台,包括接口名称、接口描述、接口URL等信息。
      • 删:管理员可以删除平台上的某个接口。
      • 改:管理员可以修改接口的信息,如接口名称、接口描述、接口URL等。
      • 查:管理员可以查看平台上所有接口的信息,包括接口名称、接口描述、接口URL等。
    • 发布接口:管理员可以发布开发完成的接口,以供接口使用者调用。
    • 测试接口:管理员可以对接口进行测试,以确保其功能的正确性和稳定性。
  • 接口使用者
    • 浏览接口:使用者可以浏览平台上的所有接口,包括接口名称、接口描述、接口URL等信息。
    • 开通接口:使用者可以开通某个接口,使其可供自己调用。
    • 调用接口:使用者可以通过接口URL调用已开通的接口,向其发送请求并获取响应。

信息管理请求

API 开放平台项目(已整理,已废弃)_第11张图片

接口调用请求 

API 开放平台项目(已整理,已废弃)_第12张图片

调用接口流程:

1、前端发送请求:在InterfaceInfo下(也就是接口详细信息)首先是点击《调用》按钮触发点击提交事件,本质上就是提交表单,所以在onfinish函数提交表单,调用invokeInterfaceInfoUsingPOST

函数发送请求(这个是根据后端invokeInterfaceInfo函数使用openapi生成)到

后端/api/interfaceInfo/invoke 。

2、后端接收请求:在controller层接收到,对请求的接口进行基本的有无/合理判断,获取当前登录用户的ak、sk,并根据yuapi-client-sdk封装好的客户端,根据登录用户的ak、sk进行

向模拟接口yuapi-interface发送请求

3、在yuapi-interface内根据ak、sk进行权限等鉴定,最后返回结果。

现在问题是:

前端发送到的地址是/api/interfaceInfo/invoke(后端backend)、但是会被API网关拦截,

目的路由是http://localhost:8123/api/name/user,后端backend也是会调用hutool发送http请求到模拟接口,,所以调用过程到底是谁调的?

--- 点击按钮请求的是前端页面,页面显示的端口是前端端口。请求到了前端之后,前端在逻辑处理里面调用后端,如果接入了网关,前端调用后端的端口应该是网关端口,从网关的策略中转发到对应的后端端口

五个模块:API网关-Web系统-模拟接口、公共模块、客户端SDK。

第六期

1、在API网关项目中,没有Mybatis,在获取用户的ak、sk需要读取数据库,想要实现在API网关项目中
快速调用其他项目中的代码,即复用其他项目代码 -- RPC
2、开发监控统计功能

怎么调用其他项目的方法?
1、复制代码和依赖、环境
2、HTTP请求(提供一个接口controller,供其他项目调用)
3、RPC
4、把公共的代码打个jar包,其他项目去引用(客户端SDK)

HTTP请求怎么调用?
1、提供方开发一个接口(地址、请求方法、参数、返回值)
2、调用方使用HTTP Client之类的代码包去发送HTTP请求

RPC
作用:像调用本地方法一样调用远程方法
1、对开发者更透明,减少了很多的沟通成本
2、RPC向远程服务器发送请求时,未必要使用HTTP协议,也可以是TCP/IP

《使用dubbo框架,运用RPC快速远程调用方法》

 API 开放平台项目(已整理,已废弃)_第13张图片

过程分析:

整合运用

zookeeper注册中心:通过内嵌的方式运行,更方便。
 最先启动注册中心,先启动provider,再启动consumer。

1、backend项目作为服务提供者,提供三个方法:
    a.实际情况是应该去数据库中查是否已分配给用户
    b.从数据库中查询模拟接口是否存在,以及请求方法是否匹配(还可以校验请求参数)
    c.调用成功,接口调用次数 + 1 invokeCount

2、gateway项目作为服务调用者,调用这3个方法

在分布式系统中,在微服务架构常见问题

  • 服务和服务地址如何进行映射和管理
  • 服务注册后,如何被及时发现
  • 服务异常时,如何进行降级
  • 服务宕机后,如何及时下线
  • 服务如何有效的水平扩展
  • 服务发现时,如何进行路由
  • 注册中心如何实现自身的高可用

一个下午和一个晚上,就干了dubbo框架下RPC服务。晚上总算是跑通了。

明天继续干。争取明天,第一个项目,终结。

*使用dubbo框架实现RPC:

Dubbo是一个高性能、轻量级的开源Java RPC框架(RPC意思是远程调用)

关键点三大类:依赖配置、启动类服务类引用类注解、注册中心nacos安装启动。

   1、消费者与提供者安装依赖(dubbo框架 & nacos注册中心);配置yml自动完成注册
        
            org.apache.dubbo
            dubbo
            3.0.9
        
        
            com.alibaba.nacos
            nacos-client
            2.1.0  
        
dubbo:
  application:
    name: dubbo-springboot-demo-provider
  protocol:
    name: dubbo
    port: -1
  registry:
    id: nacos-registry
    address: nacos://localhost:8848
   2、springboot项目启动类写@Enabledubbo;提供服务的类写@DubboService;
                消费服务@DubboReference
   3、映射接口要是相同的路径、内部声明相同的方法

提供者:映射接口com/yupi/project/provider/DemoService.java

消费者:映射接口com/yupi/project/provider/DemoService.java

        内部声明相同的方法,实现快速调用

4、实现调用

注入:

@DubboReference(check=false)
private DemoService demoService;

 API 开放平台项目(已整理,已废弃)_第14张图片        API 开放平台项目(已整理,已废弃)_第15张图片

*抽象公共服务

抽象公共服务

1、项目名:yuapi-common

2、目的:让方法、实体类在多个项目间复用,减少重复编写。

3、服务抽取:数据库中查是否已分配给用户秘钥(根据 accessKey 拿到用户信息,返回用户信息,为空表示不存在)

4、从数据库中查询模拟接口是否存在(请求路径、请求方法、请求参数,返回接口信息,为空表示不存在)

5、接口调用次数 + 1 invokeCount(accessKey、secretKey(标识用户),请求接口路径)

6、步骤:新建干净的 maven 项目,只保留必要的公共依赖抽取 service 和实体类install 本地 maven 包让服务提供者引入 common 包,测试是否正常运行让服务消费者引入 common 包

@Resource 与 @DubboReference区别:

1、@Resource是Spring中注入bean ,对象存储在容器中  (同一个项目中的引用)

2、@DubboReference是Dubbo框架下RPC引用              (不同项目中的引用)

正在写获取统计数据的操作,使用的很多新东西,没必要敲,直接看,看分析结果。

 

* 客户端SDK

主要是封装了获取请求拿到ak,sk与请求体,生成签名sign的功能。这样对于以后的项目可以直接调用。

*统计分析:

最开始通过MySQL统计,每次调用后,网关发起RPC调用,调用次数+1;

但是这样子在使用Jmeter压测工具分析时会出现调用次数统计不准确,我分析出来是由于没有在事务层面加锁,导致数据库出现并发写的问题。

想过直接在事务层面加锁,但是会大大降低效率。最后想到可以使用Redis的Zset来实现排序,其中权重参数score用来存储调用次数。

总结复习:
1、查看接口统计信息饼图还没处理好

2、扩展的点自己试着做,找大佬项目学习

3、首先是宏观:
        掌握 各个流程。
   再细节上:
        从头到尾把每个细节处理点掌握;
        代码掌握;业务逻辑!
        技术:RPC、签名认证啥的

宏观上你得明确每个技术点;细节上代码
看看参考项目要掌握哪些东西。
第一个项目,不要搞成夹生饭!!!

先业务-三层架构逻辑   -》》 再具体方法代码逻辑

*面经:

1、项目是你自己做的吗?你为什么做这样的一个项目?你做这个项目的背景(初衷)是什么?(几乎每次都被问到)
答:

        我的初衷是尽可能地帮助和服务更多的用户和开发者,让他们更加方便快捷地获取他们想要的信息和功能。接口开放平台它可以帮助开发者快速接入一些常用的服务,从而提高他们的开发效率,比如天气服务随机头像短网址等服务,它们是一些应用或者小程序中常见的功能,所以提供这些接口可以帮助开发者更加方便地实现这些功能。这些接口也可以让用户在使用应用时获得更加全面的功能和服务,从而提高他们的用户体验。所以我认为接口开放平台是一个有意义的项目,可以为用户和开发者带来更多的便利和价值。
(注:因为我个人已经将项目上线,并能够提供一些真实的接口服务。有条件的同学尽量将项目上线。此外有两场的面试官想要查看数据库,我开了屏幕共享给他们看,所以要对数据库的表结构和设计有一定的了解。)


2、项目的架构你是怎么设计的?
答:Nginx部署 + 分布式架构

        我采用前后端分离的架构,前端使用 Nginx 部署,通过 Nginx 反向代理将请求转发到 web 项目,因为项目刚刚上线,所以这里暂时采用了单机部署的模式,未来可能采取水平扩容的方式,增加多台节点,通过 Nginx 的负载均衡,将请求平均的分发到我的每个节点上,以支撑更高的并发。我的 web 项使用 Spring Boot 开发,并连接到了数据库和 Redis ,数据库使用的是 Mysql ,主要用来存储用户的信息和接口的信息;通过 redis 实现了分布式 session ,因为考虑到未来要使用分布式架构,为了避免使用 tomcat 保存 session 有用户登录失效的问题。

(注:这里我说出了反向代理,水平扩容,负载均衡等技术名词,很多面试官会根据这些名词进行延伸提问(引导面试官往自己熟悉的东西上提问)比如:说说什么是正向代理/反向代理?什么是水平扩容?什么是负载均衡?你了解哪些负载均衡的算法?提前准备好这些知识之后,就可以跟面试官一顿输出了。)
3、你怎么做的技术选型?为什么要用这些技术?
答:springboot自动装配+ MySQL存表 + Redis分布式session锁缓存

        使用 SpringBoot 是因为通过自动装配能够提高项目的开发效率,还能够很好的整合其他服务。使用 Mysql 的原因是因为考虑到未来有用户充值交易,限制调用次数等场景需要用事务保证数据的完整性和一致性。使用 Redis 的原因是因为可以用来实现分布式 session ,锁,缓存等功能。因为 Redis 是一个单独的中间件,不同客户端可以往同一个 Redis 或者集群中存放 session /加锁,这样就能保证资源能够在分布式服务下都可见。并且由于 Redis 也是单线程的,同时也支持 lua 脚本,可以保证并发安全的问题,所以可以很简单的实现分布式锁的功能。
注:被面试官追问自动装配的原理你了解过吗?自动装配是怎么实现的?分布式 session 的原理?


4、你的开发流程是什么?先实现还是先技术选型?
答:参考现有结合自己 + 先产品后技术。技术为业务服务!

        我先参考了一些已有的产品,根据这些产品,总结出来比较好的功能点,再结合自己想要实现的一些功能特色,去做了一个项目整体设计,有了产品原型后再进行技术选型。使用什么样的技术去解决什么样的业务问题。


5、为什么你要使用网关?
答:隐藏真实接口地址 + 全局管理鉴权路由访控流控等功能

        我这个平台的关键点就在于提供接口服务,要保证接口的可用性和稳定性,所以将接口服务独立部署在另一台机器上,隐藏真实的接口地址及端口,调用接口服务的请求都必须经过网关流量染色之后..(这里细节太多,比如 rpc 调用获取用户 sk ,重新生成签名认证等等)之后,将请求转发到真实的接口地址,防止接口被恶意调用、盗刷。
(注:这个问题要对网关做了什么事情非常非常熟悉,建议反复观看鱼皮大佬的直播回放。)


6、为什么使用 RPC 调用?有了解过其他的方式吗?
答:调用操作数据库服务 + Open Feign

        网关内签名认证,验证接口等功能需要操作数据库,因为如果在网关引入数据库的操作的话,不仅会增加项目体积,而且违背了设计原则单一职责原则,所以我考虑通过服务间调用的方式,常见有两种方式,第一种是 Open feign ,原理是构造了一个 HTTP 请求,并会添加很多的请求头, body 是使用 json 字符串传输,所以调用效率会比较低,更加适合外部服务间的调用。然后我了解到 RPC 是可以基于 TCP 协议,避免了无用的请求头,以及可以通过将数据序列化为二进制流的形式传输,效率更加高效,更加安全,所以更适用于我这个场景。最终我选择了 Dubbo RPC 框架来实现这个功能。


7、你的接口调用次数统计以及排行是怎么实现的?
答:

        通过 Mysql 统计,每次调用结束后,网关都会发起一个 rpc 请求,调用次数+1。
注:这里我会抛出一个设计缺陷,在实际测试过程中,通过 jmeter 压测工具,会出现调用次数不准的情况,原因是因为没有在业务层面加锁,导致数据库出现并发写的问题。并且并发量大的话,对数据库造成很大的压力。引导面试官问出,那你有什么更好的解决方案吗?
答:如果在业务层面加一个写锁的话,会影响业务的执行效率,所以我想使用 Redis 去解决, Redis 有一个数据结构 Zset 支持排序, score 可以用来存储调用次数,并且 Redis 是单线程,可以解决并发问题。
注:这里被追问过 Zset 的底层实现,以及如何将这些数据进行持久化保存,防止 Redis 宕机导致数据丢失,可以从 AOF , RDB 展开来讲,或者在后台开启一个定时任务,定时将这些数据进行落库。


8、你做过什么优化吗?你接口的性能怎么样?

答:修改存储引擎

        我有一个接口是随机返回土味情话,我在数据库中插入了几千条土味情话,当调用接口时随机返回一条。在还没有优化前,接口的 qps 在300左右,但是考虑到这个接口只有读操作,没有增删改操作,所以我将这张表的存储引擎从 Innodb 改为了 MyISAM ,接口的 qps 提升到了1500。
(注:被面试官追问为什么改为 MyISAM 有这么大的性能提升? Innodb 和 MyISAM 有什么区别?这个问题一定要根据自己实际情况来答,根据自己擅长的方面,比如对查询语句做了索引优化,提升了接口的性能。)


总而言之,面试官会从各个角度去深挖项目的细节,考量你是不是真的自己做的,是不是真的理解?所以要做到对项目的所有细节都非常的熟悉。当完全理解项目之后,就能够提前预测到面试官会怎么问,并在面试过程中说出一些技术名词引导面试官,然后对这些问题,和延伸的知识点能够完全掌握后,相信一定可以征服面试官。

你可能感兴趣的:(鱼皮项目笔记,1024程序员节)