이 글에서는 API를 설계할 때 주의해야 할 사항을 주로 소개합니다. 우아한 API 인터페이스를 디자인하는 방법에 관심이 있는 분들을 위해 아래 내용을 살펴보겠습니다.
실제 작업에서는 종종 타사 플랫폼을 처리해야 하며, 타사 플랫폼 API 인터페이스에 연결하거나 타사 플랫폼 호출을 위한 API 인터페이스를 제공할 수도 있습니다.
그럼 질문은 우아한 API 인터페이스를 디자인하면 보안, 반복 가능한 호출, 안정성, 좋은 위치 지정 등 다양한 요구 사항을 충족할 수 있느냐는 것입니다.
오늘은 API 인터페이스를 디자인할 때 주의해야 할 사항에 대해 말씀드리겠습니다. 도움이 되셨으면 좋겠습니다.
API 인터페이스의 데이터가 변조되는 것을 방지하려면 API 인터페이스에 서명
해야 하는 경우가 많습니다. 签名
。
接口请求方将请求参数
+ 时间戳
+ 密钥
拼接成一个字符串,然后通过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。
有些时候,我们的API接口直接传递的非常重要的数据,比如:用户的银行卡号、转账金额、用户身份证等,如果将这些参数,直接明文,暴露到公网上是非常危险的事情。
由此,我们需要对数据进行加密
。
目前使用比较多的是用BASE64
加解密。
我们可以将所有的数据,安装一定的规律拼接成一个大的字符串,然后在加一个密钥
,拼接到一起。
然后使用JDK1.8之后的Base64工具类处理,效果如下:
【加密前的数据】www.baidu.com 【加密后的数据】d3d3LmJhaWR1LmNvbQ==复制代码
为了安全性,使用Base64可以加密多次。
API接口的调用方在传递参数时,body中只有一个参数data,它就是base64之后的加密数据。
API接口的网关服务,在接收到data数据后,根据双方事先预定的密钥、加密算法、加密次数等,进行解密,并且反序列化出参数数据。
为了进一步加强API接口的安全性,防止接口的签名或者加密被破解了,攻击者可以在自己的服务器上请求该接口。
需求限制请求ip
,增加ip白名单
。
只有在白名单中的ip地址,才能成功请求API接口,否则直接返回无访问权限。
ip白名单也可以加在API网关服务上。
但也要防止公司的内部应用服务器被攻破,这种情况也可以从内部服务器上发起API接口的请求。
这时候就需要增加web防火墙了,比如:ModSecurity等。
如果你的API接口被第三方平台调用了,这就意味着着,调用频率是没法控制的。
第三方平台调用你的API接口时,如果并发量一下子太高,可能会导致你的API服务不可用,接口直接挂掉。
由此,必须要对API接口做限流
。
限流方法有三种:
对请求ip做限流:比如同一个ip,在一分钟内,对API接口总的请求次数
,不能超过10000次。
对请求接口做限流:比如同一个ip,在一分钟内,对指定的API接口
,请求次数不能超过2000次。
对请求用户做限流:比如同一个AK/SK用户
요청 매개변수
+ 타임스탬프
+ 키
를 문자열로 연결한 다음 md5
Wait를 전달합니다. 이전 기호를 생성하는 해시 알고리즘. 🎜🎜그런 다음 요청 매개변수 또는 요청 헤더에 서명 매개변수를 추가하고 이를 API 인터페이스에 전달합니다. 🎜🎜API 인터페이스의 게이트웨이 서비스는 부호 값을 얻은 다음 동일한 요청 매개변수 + 타임스탬프 + 키를 사용하여 이를 문자열로 연결하고 동일한 m5 알고리즘을 사용하여 다른 부호를 생성하고 두 부호 값을 비교합니다. 그들이 동일한지 확인하세요. 🎜🎜두 부호가 같으면 유효한 요청으로 간주되며 API 인터페이스의 게이트웨이 서비스는 요청을 해당 비즈니스 시스템으로 전달합니다. 🎜🎜두 기호가 같지 않으면 API 인터페이스의 게이트웨이 서비스가 직접 서명 오류를 반환합니다. 🎜🎜질문은: 서명에 타임스탬프를 추가해야 하는 이유는 무엇입니까? 🎜🎜답변: 보안상의 이유로 동일한 요청이 반복적으로 사용되는 것을 방지하고 키가 해독되지 않을 가능성을 높이려면 각 요청에 대해 합리적인 만료 시간(예: 15분)을 설정해야 합니다. 🎜🎜 이러한 요청은 15분 이내에 유효합니다. 15분을 초과하면 API 인터페이스의 게이트웨이 서비스는 유효 기간이 만료되었음을 나타내는 예외 프롬프트를 반환합니다. 🎜🎜현재 서명 생성에 사용되는 키에는 두 가지 형태가 있습니다. 🎜🎜하나는 양 당사자가 고정 값 privateKey에 동의한다는 것입니다. 🎜🎜다른 하나는 API 인터페이스 제공자가 AK/SK 두 가지 값을 제공하고 양 당사자가 서명의 키로 SK를 사용하는 데 동의한다는 것입니다. AK 인터페이스 호출자는 이를 헤더의 accessKey로 API 인터페이스 제공자에게 전달하므로 API 인터페이스 제공자는 AK를 기반으로 SK를 획득하고 새 sgin을 생성할 수 있습니다. 🎜암호화
해야 합니다. 🎜🎜현재 암호화 및 복호화에는 BASE64
가 사용됩니다. 🎜🎜특정 규칙에 따라 모든 데이터를 큰 문자열로 엮은 다음 키
를 추가하여 함께 엮을 수 있습니다. 🎜🎜그런 다음 JDK1.8 이후의 Base64 도구 클래스를 사용하여 처리하면 다음과 같습니다. 🎜{ "code":0, "message":null, "data":[{"id":123,"name":"abc"}] },🎜보안을 위해 Base64를 사용하여 여러 번 암호화할 수 있습니다. 🎜🎜API 인터페이스의 호출자가 매개변수를 전달할 때 본문에는 매개변수 데이터가 하나만 있는데, 이는 base64 이후에 암호화된 데이터입니다. 🎜🎜API 인터페이스의 게이트웨이 서비스는 데이터 데이터를 수신한 후 양측이 미리 결정한 키, 암호화 알고리즘, 암호화 시간 등에 따라 이를 해독하고 매개변수 데이터를 역직렬화합니다. 🎜
ip
를 요청하고 ip 허용 목록
을 추가하세요. 🎜🎜화이트리스트에 있는 IP 주소만 API 인터페이스를 성공적으로 요청할 수 있습니다. 그렇지 않으면 액세스 권한이 직접 반환되지 않습니다. 🎜🎜IP 화이트리스트를 API 게이트웨이 서비스에 추가할 수도 있습니다. 🎜🎜하지만 회사 내부 애플리케이션 서버가 침해되는 것도 방지해야 합니다. 이 경우 내부 서버에서 API 인터페이스 요청이 시작될 수도 있습니다. 🎜🎜이때 ModSecurity 등 웹 방화벽을 추가해야 합니다. 🎜현재 제한
이 필요합니다. 🎜🎜현재 제한 방법에는 세 가지가 있습니다. 🎜API 인터페이스에 대한 총 요청 수
는 10,000을 초과할 수 없습니다. 🎜지정된 API 인터페이스
에 대한 요청 수가 2,000회를 초과할 수 없습니다. 🎜AK/SK 사용자
는 1분 동안 API 인터페이스에 10,000개 이하의 요청을 보낼 수 있습니다. 🎜我们在实际工作中,可以通过nginx
,redis
或者gateway
实现限流的功能。
我们需要对API接口做参数校验
,比如:校验必填字段是否为空,校验字段类型,校验字段长度,校验枚举值等等。
这样做可以拦截一些无效的请求。
比如在新增数据时,字段长度超过了数据字段的最大长度,数据库会直接报错。
但这种异常的请求,我们完全可以在API接口的前期进行识别,没有必要走到数据库保存数据那一步,浪费系统资源。
有些金额字段,本来是正数,但如果用户传入了负数,万一接口没做校验,可能会导致一些没必要的损失。
还有些状态字段,如果不做校验,用户如果传入了系统中不存在的枚举值,就会导致保存的数据异常。
由此可见,做参数校验是非常有必要的。
在Java中校验数据使用最多的是hiberate
的Validator
框架,它里面包含了@Null、@NotEmpty、@Size、@Max、@Min等注解。
用它们校验数据非常方便。
当然有些日期字段和枚举字段,可能需要通过自定义注解的方式实现参数校验。
我之前调用过别人的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网关捕获该业务异常,然后转换成统一的异常结构返回,这样能统一返回值结构。
我们的API接口需要对异常
进行统一处理。
不知道你有没有遇到过这种场景:有时候在API接口中,需要访问数据库,但表不存在,或者sql语句异常,就会直接把sql信息在API接口中直接返回。
返回值中包含了异常堆栈信息
、数据库信息
、错误代码和行数
等信息。
如果直接把这些内容暴露给第三方平台,是很危险的事情。
有些不法分子,利用接口返回值中的这些信息,有可能会进行sql注入或者直接脱库,而对我们系统造成一定的损失。
因此非常有必要对API接口中的异常做统一处理,把异常转换成这样:
{ "code":500, "message":"服务器内部错误", "data":null }
返回码code
是500
,返回信息message
是服务器内部异常
。
这样第三方平台就知道是API接口出现了内部问题,但不知道具体原因,他们可以找我们排查问题。
我们可以在内部的日志文件中,把堆栈信息、数据库信息、错误代码行数等信息,打印出来。
我们可以在gateway
中对异常进行拦截,做统一封装,然后给第三方平台的是处理后没有敏感信息的错误信息。
在第三方平台请求你的API接口时,接口的请求日志非常重要,通过它可以快速的分析和定位问题。
我们需要把API接口的请求url、请求参数、请求头、请求方式、响应数据和响应时间等,记录到日志文件中。
最好有traceId
,可以通过它串联整个请求的日志,过滤多余的日志。
当然有些时候,请求日志不光是你们公司开发人员需要查看,第三方平台的用户也需要能查看接口的请求日志。
这时就需要把日志落地到数据库,比如:mongodb
或者elastic search
,然后做一个UI页面,给第三方平台的用户开通查看权限。这样他们就能在外网查看请求日志了,他们自己也能定位一部分问题。
제3자 플랫폼은 매우 짧은 시간 내에 인터페이스를 여러 번 요청할 가능성이 높습니다(예: 1초에 두 번). 비즈니스 시스템에 버그가 있거나 인터페이스 호출에 실패한 후 다시 시도하는 것일 수 있으므로 API 인터페이스는 멱등성
이어야 합니다. 幂等设计
。
也就是说要支持在极短的时间内,第三方平台用相同的参数请求API接口多次,第一次请求数据库会新增数据,但第二次请求以后就不会新增数据,但也会返回成功。
这样做的目的是不会产生错误数据。
我们在日常工作中,可以通过在数据库
中增加唯一索引
,或者在redis
保存requestId
和请求参来保证接口幂等性。
对接口幂等性感兴趣的小伙伴,可以看看我的另一篇文章《高并发下如何保证接口的幂等性?》,里面有非常详细的介绍。
对于对我提供的批量接口,一定要限制请求的记录条数
。
如果请求的数据太多,很容易造成API接口超时
等问题,让API接口变得不稳定。
通常情况下,建议一次请求中的参数,最多支持传入500条记录。
如果用户传入多余500条记录,则接口直接给出提示。
建议这个参数做成可配置的,并且要事先跟第三方平台协商好,避免上线后产生不必要的问题。
上线前我们务必要对API接口做一下压力测试
,知道各个接口的qps
情况。
以便于我们能够更好的预估,需要部署多少服务器节点,对于API接口的稳定性至关重要。
之前虽说对API接口做了限流,但是实际上API接口是否能够达到限制的阀值,这是一个问号,如果不做压力测试,是有很大风险的。
比如:你API接口限流1秒只允许50次请求,但实际API接口只能处理30次请求,这样你的API接口也会处理不过来。
我们在工作中可以用jmeter
或者apache benc
对API接口做压力测试。
一般的API接口的逻辑都是同步处理的,请求完之后立刻返回结果。
但有时候,我们的API接口里面的业务逻辑非常复杂,特别是有些批量接口,如果同步处理业务,耗时会非常长。
这种情况下,为了提升API接口的性能,我们可以改成异步处理
。
在API接口中可以发送一条mq消息
,然后直接返回成功。之后,有个专门的mq消费者
去异步消费该消息,做业务逻辑处理。
直接异步处理的接口,第三方平台有两种方式获取到。
第一种方式是:我们回调
第三方平台的接口,告知他们API接口的处理结果,很多支付接口就是这么玩的。
第二种方式是:第三方平台通过轮询
调用我们另外一个查询状态的API接口,每隔一段时间查询一次状态,传入的参数是之前的那个API接口中的id集合。
有时候第三方平台调用我们API接口时,获取的数据中有一部分是敏感数据,比如:用户手机号、银行卡号等等。
这样信息如果通过API接口直接保留到外网,是非常不安全的,很容易造成用户隐私数据泄露的问题。
这就需要对部分数据做数据脱敏
了。
我们可以在返回的数据中,部分内容用星号
代替。
已用户手机号为例:182****887
데이터베이스
에 고유 인덱스
를 추가하거나 redis
에 requestId
를 저장하고 요청할 수 있습니다. 인터페이스 멱등성을 보장하는 매개변수입니다. 인터페이스 멱등성에 관심이 있는 친구는 내 다른 기사 "멱등성을 보장하는 방법 동시성이 높은 인터페이스의 수는 무엇입니까? '에 매우 자세한 소개가 나와 있습니다.
요청하는 레코드 수를 제한
하세요. 너무 많은 데이터를 요청하면 API 인터페이스 시간 초과
등의 문제가 발생하고 API 인터페이스가 불안정해지기 쉽습니다.
사용자가 500개 이상의 레코드를 입력하면 인터페이스에서 직접 프롬프트를 표시합니다.
스트레스 테스트
를 수행하여 qps
를 알아야 합니다. > 각 인터페이스 > 상황. jmeter
또는 apache benc
를 사용하여 직장에서 API 인터페이스에 대한 스트레스 테스트를 수행할 수 있습니다. 일반 API 인터페이스 로직은 동기적으로 처리되며, 요청이 완료되는 즉시 결과가 반환됩니다.
이 경우 API 인터페이스의 성능 향상을 위해 비동기 처리
로 변경할 수 있습니다.
mq 메시지
를 보낸 다음 바로 성공을 반환할 수 있습니다. 그 다음에는 메시지를 비동기적으로 소비하고 비즈니스 로직 처리를 수행하는 전용 mq 소비자
가 있습니다. 🎜🎜타사 플랫폼은 두 가지 방법으로 직접 비동기 처리 인터페이스를 얻을 수 있습니다. 🎜🎜첫 번째 방법은 제3자 플랫폼의 인터페이스를 콜백
하여 API 인터페이스의 처리 결과를 알리는 것입니다. 이것이 작동하는 결제 인터페이스의 수입니다. 🎜🎜두 번째 방법은 제3자 플랫폼이 폴링
을 통해 상태를 쿼리하기 위해 다른 API 인터페이스를 호출하고 가끔씩 상태를 쿼리하는 것입니다. 전달된 매개변수는 이전 API 인터페이스에서 가져온 것입니다. .아이디 컬렉션. 🎜데이터 둔감화
가 필요합니다. 🎜🎜반환된 데이터에서 콘텐츠의 일부를 별표
로 바꿀 수 있습니다. 🎜🎜사용자의 휴대폰 번호를 예로 들어 보겠습니다: 182****887
. 🎜🎜이렇게 하면 데이터가 유출되더라도 일부만 유출될 뿐, 범죄자들이 이 데이터를 얻는 것은 무용지물이 될 것입니다. 🎜🎜14. 완전한 인터페이스 문서🎜🎜솔직히, 완전한 API 인터페이스 문서는 통신 비용을 많이 줄이고 두 당사자가 인터페이스 도킹을 수행할 때 상대방이 여러 번 우회하는 것을 방지할 수 있습니다. 🎜🎜다음 정보가 인터페이스 문서에 포함되어야 합니다. 🎜🎜🎜🎜인터페이스 주소 🎜🎜🎜🎜요청 방법(예: 게시 또는 가져오기 반환 코드 및 오류 메시지🎜🎜🎜🎜암호화 또는 서명 예🎜🎜🎜🎜) 전체 요청 데모🎜IP 화이트리스트 열기와 같은 추가 지침.
인터페이스 문서의 인터페이스 및 필드 이름 명명 스타일을 통일하는 것이 가장 좋습니다. 예를 들어 驼峰标识
를 사용하여 이름을 지정합니다.
필드 유형과 길이를 통일합니다. 예: id 필드는 Long 유형을 사용하고 길이는 20으로 지정됩니다. 상태 필드는 고정 길이 2 등의 int 유형을 사용합니다.
균일한 시간 형식 필드(예: 시간은 문자열 유형을 사용하며 형식은 yyyy-MM-dd HH:mm:ss)입니다.
인터페이스 문서에 AK/SK 및 도메인 이름을 표시하고, 별도 제공을 요청하는 등의 작업을 수행합니다.
추천 학습: "PHP 비디오 튜토리얼"
위 내용은 API 인터페이스를 디자인할 때 이런 부분에 주의하세요!의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!