首页 > 其他分享 >瞧瞧别人的 Controller,那叫一个优雅!

瞧瞧别人的 Controller,那叫一个优雅!

时间:2024-11-14 19:30:47浏览次数:1  
标签:请求 校验 接口 优雅 瞧瞧 Controller API com 第三方

前言

在实际工作中,我们需要经常跟第三方平台打交道,可能会对接第三方平台 Controller 接口,或者提供 Controller 接口给第三方平台调用。

那么问题来了,如果设计一个优雅的 Controller 接口,能够满足:安全性、可重复调用、稳定性、好定位问题等多方面需求?

今天跟大家一起聊聊设计 Controller 接口时,需要注意的一些地方,希望对你会有所帮助。

  1. 签名

为了防止 Controller 接口中的数据被篡改,很多时候我们需要对 Controller 接口做签名。

接口请求方将请求参数 + 时间戳 + 密钥拼接成一个字符串,然后通过md5等 hash 算法,生成一个前面 sign。

然后在请求参数或者请求头中,增加 sign 参数,传递给 API 接口。

API 接口的网关服务,获取到该 sign 值,然后用相同的请求参数 + 时间戳 + 密钥拼接成一个字符串,用相同的 m5 算法生成另外一个 sign,对比两个 sign 值是否相等。

如果两个 sign 相等,则认为是有效请求,API 接口的网关服务会将给请求转发给相应的业务系统。

如果两个 sign 不相等,则 API 接口的网关服务会直接返回签名错误。

问题来了:签名中为什么要加时间戳?

答:为了安全性考虑,防止同一次请求被反复利用,增加了密钥没破解的可能性,我们必须要对每次请求都设置一个合理的过期时间,比如:15 分钟。

这样一次请求,在 15 分钟之内是有效的,超过 15 分钟,API 接口的网关服务会返回超过有效期的异常提示。

目前生成签名中的密钥有两种形式:

一种是双方约定一个固定值 privateKey。

另一种是 API 接口提供方给出 AK/SK 两个值,双方约定用 SK 作为签名中的密钥。AK 接口调用方作为 header 中的 accessKey 传递给 API 接口提供方,这样 API 接口提供方可以根据 AK 获取到 SK,而生成新的 sgin。

  1. 加密

有些时候,我们的 Controller 接口直接传递的非常重要的数据,比如:用户的登录密码、银行卡号、转账金额、用户身份证等,如果将这些参数,直接明文,暴露到公网上是非常危险的事情。

由此,我们需要对数据进行非对称加密。

目前使用比较多的是用RSA。

RSA 包含了一对:公钥和私钥。

我们以用户登录密码为例。

在用户输入密码之后,在前端需要对密码使用公钥做加密处理。

公钥是保留在前端代码中的,即使泄露给别人了,也没关系。

因为使用公钥加密后的密码,只能使用后端服务中对应的私钥才能解密。

而我们私钥保存在后端服务的配置中,别人无法获取到。

因此,使用 RSA 加密和解密是安全的。

我们可以使用在线工具生成密钥对:https://tools.ytdevops.com/rsa-key-pair-generator

  1. ip 白名单

为了进一步加强 API 接口的安全性,防止接口的签名或者加密被破解了,攻击者可以在自己的服务器上请求该接口。

需求限制请求ip,增加ip白名单。

只有在白名单中的 ip 地址,才能成功请求 API 接口,否则直接返回无访问权限。

ip 白名单也可以加在 API 网关服务上。

但也要防止公司的内部应用服务器被攻破,这种情况也可以从内部服务器上发起 API 接口的请求。

这时候就需要增加 web 防火墙了,比如:ModSecurity 等。

  1. 限流

如果你的 API 接口被第三方平台调用了,这就意味着着,调用频率是没法控制的。

第三方平台调用你的 API 接口时,如果并发量一下子太高,可能会导致你的 API 服务不可用,接口直接挂掉。

由此,必须要对 API 接口做限流。

限流方法有三种:

对请求 ip 做限流:比如同一个 ip,在一分钟内,对API接口总的请求次数,不能超过 10000 次。

对请求接口做限流:比如同一个 ip,在一分钟内,对指定的API接口,请求次数不能超过 2000 次。

对请求用户做限流:比如同一个AK/SK用户,在一分钟内,对 API 接口总的请求次数,不能超过 10000 次。

我们在实际工作中,可以通过nginx,redis或者gateway实现限流的功能。

  1. 参数校验

我们需要对 API 接口做参数校验,比如:校验必填字段是否为空,校验字段类型,校验字段长度,校验枚举值等等。

这样做可以拦截一些无效的请求。

比如在新增数据时,字段长度超过了数据字段的最大长度,数据库会直接报错。

但这种异常的请求,我们完全可以在 API 接口的前期进行识别,没有必要走到数据库保存数据那一步,浪费系统资源。

有些金额字段,本来是正数,但如果用户传入了负数,万一接口没做校验,可能会导致一些没必要的损失。

还有些状态字段,如果不做校验,用户如果传入了系统中不存在的枚举值,就会导致保存的数据异常。

由此可见,做参数校验是非常有必要的。

在 Java 中校验数据使用最多的是hiberate的Validator框架,它里面包含了 @Null、@NotEmpty、@Size、@Max、@Min 等注解。

用它们校验数据非常方便。

当然有些日期字段和枚举字段,可能需要通过自定义注解的方式实现参数校验。

  1. 统一返回值

我之前调用过别人的 API 接口,正常返回数据是一种 json 格式,比如:

{
"code":0,
"message":null,
"data":[{"id":123,"name":"abc"}]
},

签名错误返回的 json 格式:

{
"code":1001,
"message":"签名错误",
"data":null
}

没有数据权限返回的 json 格式:

{
"rt":10,
"errorMgt":"没有权限",
"result":null
}

这种是比较坑的做法,返回值中有多种不同格式的返回数据,这样会导致对接方很难理解。

出现这种情况,可能是 API 网关定义了一直返回值结构,业务系统定义了另外一种返回值结构。如果是网关异常,则返回网关定义的返回值结构,如果是业务系统异常,则返回业务系统的返回值结构。

但这样会导致 API 接口出现不同的异常时,返回不同的返回值结构,非常不利于接口的维护。

其实这个问题我们可以在设计API网关时解决。

业务系统在出现异常时,抛出业务异常的 RuntimeException,其中有个 message 字段定义异常信息。

所有的 API 接口都必须经过 API 网关,API 网关捕获该业务异常,然后转换成统一的异常结构返回,这样能统一返回值结构。

  1. 统一封装异常

我们的 API 接口需要对异常进行统一处理。

不知道你有没有遇到过这种场景:有时候在 API 接口中,需要访问数据库,但表不存在,或者 sql 语句异常,就会直接把 sql 信息在 API 接口中直接返回。

返回值中包含了异常堆栈信息、数据库信息、错误代码和行数等信息。

如果直接把这些内容暴露给第三方平台,是很危险的事情。

有些不法分子,利用接口返回值中的这些信息,有可能会进行 sql 注入或者直接脱库,而对我们系统造成一定的损失。

因此非常有必要对 API 接口中的异常做统一处理,把异常转换成这样:

{
"code":500,
"message":"服务器内部错误",
"data":null
}

返回码code是500,返回信息message是服务器内部异常。

这样第三方平台就知道是 API 接口出现了内部问题,但不知道具体原因,他们可以找我们排查问题。

我们可以在内部的日志文件中,把堆栈信息、数据库信息、错误代码行数等信息,打印出来。

我们可以在gateway中对异常进行拦截,做统一封装,然后给第三方平台的是处理后没有敏感信息的错误信息。

  1. 请求日志

在第三方平台请求你的 API 接口时,接口的请求日志非常重要,通过它可以快速的分析和定位问题。

我们需要把 API 接口的请求 url、请求参数、请求头、请求方式、响应数据和响应时间等,记录到日志文件中。

最好有traceId,可以通过它串联整个请求的日志,过滤多余的日志。

当然有些时候,请求日志不光是你们公司开发人员需要查看,第三方平台的用户也需要能查看接口的请求日志。

这时就需要把日志落地到数据库,比如:mongodb或者elastic search,然后做一个 UI 页面,给第三方平台的用户开通查看权限。这样他们就能在外网查看请求日志了,他们自己也能定位一部分问题。

  1. 幂等设计

第三方平台极有可能在极短的时间内,请求我们接口多次,比如:在 1 秒内请求两次。有可能是他们业务系统有 bug,或者在做接口调用失败重试,因此我们的 API 接口需要做幂等设计。

也就是说要支持在极短的时间内,第三方平台用相同的参数请求 API 接口多次,第一次请求数据库会新增数据,但第二次请求以后就不会新增数据,但也会返回成功。

这样做的目的是不会产生错误数据。
cegf.mxy998.com,cegf.gjkds.com,cegf.mbslzp.com
cegf.sh-soyun.com,cegf.clzyfc.com

我们在日常工作中,可以通过在数据库中增加唯一索引,或者在redis保存requestId和请求参来保证接口幂等性。

  1. 限制记录条数

对于对我提供的批量接口,一定要限制请求的记录条数。

如果请求的数据太多,很容易造成 API接口超时等问题,让 API 接口变得不稳定。

通常情况下,建议一次请求中的参数,最多支持传入 500 条记录。

如果用户传入多余 500 条记录,则接口直接给出提示。

建议这个参数做成可配置的,并且要事先跟第三方平台协商好,避免上线后产生不必要的问题。

  1. 压测

上线前我们务必要对 API 接口做一下压力测试,知道各个接口的qps情况。

以便于我们能够更好的预估,需要部署多少服务器节点,对于 API 接口的稳定性至关重要。

之前虽说对 API 接口做了限流,但是实际上 API 接口是否能够达到限制的阀值,这是一个问号,如果不做压力测试,是有很大风险的。

比如:你 API 接口限流 1 秒只允许 50 次请求,但实际 API 接口只能处理 30 次请求,这样你的 API 接口也会处理不过来。

我们在工作中可以用jmeter或者apache benc对 API 接口做压力测试。

  1. 异步处理

一般的 API 接口的逻辑都是同步处理的,请求完之后立刻返回结果。

但有时候,我们的 API 接口里面的业务逻辑非常复杂,特别是有些批量接口,如果同步处理业务,耗时会非常长。

这种情况下,为了提升 API 接口的性能,我们可以改成异步处理。

在 API 接口中可以发送一条mq消息,然后直接返回成功。之后,有个专门的mq消费者去异步消费该消息,做业务逻辑处理。

直接异步处理的接口,第三方平台有两种方式获取到。

第一种方式是:我们回调第三方平台的接口,告知他们 API 接口的处理结果,很多支付接口就是这么玩的。

第二种方式是:第三方平台通过轮询调用我们另外一个查询状态的 API 接口,每隔一段时间查询一次状态,传入的参数是之前的那个 API 接口中的 id 集合。

  1. 数据脱敏

有时候第三方平台调用我们 API 接口时,获取的数据中有一部分是敏感数据,比如:用户手机号、银行卡号等等。

这样信息如果通过 API 接口直接保留到外网,是非常不安全的,很容易造成用户隐私数据泄露的问题。

这就需要对部分数据做数据脱敏了。

我们可以在返回的数据中,部分内容用星号代替。

已用户手机号为例:182****887。

这样即使数据被泄露了,也只泄露了一部分,不法分子拿到这份数据也没啥用。

  1. 完整的接口文档

说实话,一份完整的 API 接口文档,在双方做接口对接时,可以减少很多沟通成本,让对方少走很多弯路。

接口文档中需要包含如下信息:

接口地址

请求方式,比如:post 或 get

请求参数和字段介绍

返回值和字段介绍

返回码和错误信息

加密或签名示例

完整的请求 demo

额外的说明,比如:开通 ip 白名单。
cegf.ousnled.com,cegf.syshuangyihe.com,cegf.eyeql.com
cegf.xyfhm.com,cegf.nc-lh.com

接口文档中最好能够统一接口和字段名称的命名风格,比如都用驼峰标识命名。

接口地址中可以加一个版本号 v1,比如:v1/query/getCategory,这样以后接口有很大的变动,可以非常方便升级版本。

统一字段的类型和长度,比如:id 字段用 Long 类型,长度规定 20。status 字段用 int 类型,长度固定 2 等。

统一时间格式字段,比如:time 用 String 类型,格式为:yyyy-MM-dd HH:mm:ss。

接口文档中写明 AK/SK 和域名,找某某单独提供等。

文章转载自:苏三说技术

原文链接:https://www.cnblogs.com/12lisu/p/18541375

体验地址:http://www.jnpfsoft.com/?from=infoq

标签:请求,校验,接口,优雅,瞧瞧,Controller,API,com,第三方
From: https://www.cnblogs.com/bkbk1234/p/18546630

相关文章

  • 瞧瞧别人的Controller,那叫一个优雅!
    瞧瞧别人的Controller,那叫一个优雅! 前言在实际工作中,我们需要经常跟第三方平台打交道,可能会对接第三方平台Controller接口,或者提供Controller接口给第三方平台调用。那么问题来了,如果设计一个优雅的Controller接口,能够满足:安全性、可重复调用、稳定性、好定位问题等多方面......
  • 瞧瞧别人的Controller,那叫一个优雅!
    前言在实际工作中,我们需要经常跟第三方平台打交道,可能会对接第三方平台Controller接口,或者提供Controller接口给第三方平台调用。那么问题来了,如果设计一个优雅的Controller接口,能够满足:安全性、可重复调用、稳定性、好定位问题等多方面需求?今天跟大家一起聊聊设计Controller接......
  • 带参数的 Python 装饰器让你的代码更优雅
    引言在上一篇文章中,我们介绍了Python装饰器的基本概念及其简单用法。前面讲到的装饰器都是不带参数的装饰器,在需要对装饰器做一些针对性的处理的时候就不太适用了,这个时候需要对装饰器传入一些参数,根据传入的参数进行不同的处理。带参数装饰器在实际开发中能够灵活地调整函数......
  • macOS 如何优雅地配置Java开发环境.md
    一、准备确保HomeBrew存在以下命令即可安装HomeBrewexportHOMEBREW_BREW_GIT_REMOTE="https://mirrors.ustc.edu.cn/brew.git"exportHOMEBREW_CORE_GIT_REMOTE="https://mirrors.ustc.edu.cn/homebrew-core.git"exportHOMEBREW_API_DOMAIN="https://mirro......
  • 【Java深度揭秘】掌握SPI机制,让你的代码设计更优雅!
    SPI(ServiceProviderInterface)机制是Java中一种服务发现和加载的机制,它允许第三方为应用程序提供实现。SPI机制广泛应用于Java标准库以及各种框架中,如JDBC、JNDI等。SPI机制的基本概念接口定义:首先定义一个接口,这个接口规定了服务提供者需要实现的方法。配置文件:在META-INF/......
  • P6667 [清华集训2016] 如何优雅地求和 题解
    一道非常有启发性的题目。思路考虑对于一个给出点值的多项式函数如何处理。我们发现,对于一个\(m\)次多项式\(f(x)\),由于\(\binom{x}{i}\)为\(i\)次多项式,所以说我们必定可以把一个多项式函数写成如下模样:\[F(k)=\sum_{i=0}^m\binom{k}{i}f_i\]可以看出,\(f_i\)实际上......
  • 红黑树的平衡之舞:数据结构中的优雅艺术
    文章目录前言......
  • 你肯定不知道:Vue多文件上传时拖放操作的优雅处理
            多文件上传是Vue应用的常见操作。操作要求:(1)允许反复拖放多个文件到待上传区域(2)自动过滤掉重复拖放的文件(3)拖放后,形成待上传文件列表的简易缩略图(4)双击文件名,可移去某个文件。具体效果,如下图所示。        我们可将拖放操作设计为一个插件指令dragDro......
  • Pinctrl子系统中Pincontroller和client驱动程序的编写
    往期内容本专栏往期内容:Pinctrl子系统和其主要结构体引入Pinctrl子系统pinctrl_desc结构体进一步介绍Pinctrl子系统中client端设备树相关数据结构介绍和解析inctrl子系统中Pincontroller构造过程驱动分析:imx_pinctrl_soc_info结构体Pinctrl子系统中client端使用pinctrl过......
  • 算法妙妙屋-------1.递归的深邃回响:C++ 算法世界的优雅之旅
    前言:递归是一种在算法中广泛应用的思想,其主体思想是通过将复杂的问题分解为更简单的子问题来求解。具体而言,递归通常包括以下几个要素:基本情况(BaseCase):每个递归算法必须有一个或多个基本情况,用于定义何时停止递归。基本情况是问题的最小实例,直接返回结果,不再进行进一......