This article brings you relevant knowledge about APIs. It mainly introduces what should be paid attention to when designing APIs? For those who are interested in how to design an elegant API interface, let’s take a look below. I hope it will be helpful to everyone.
In actual work, we often need to deal with third-party platforms, and may connect to third-party platform API interfaces, or provide API interfaces for third-party platform calls.
Then the question is, if you design an elegant API interface, can it meet various needs such as security, repeatable callability, stability, and good positioning?
Today I will talk with you about some things that need to be paid attention to when designing API interfaces. I hope it will be helpful to you.
In order to prevent the data in the API interface from being tampered with, many times we need to sign
the API interface.
The interface requester concatenates request parameters
timestamp
key
into a string, and then passes md5
etc. The hash algorithm generates a previous sign.
Then add the sign parameter to the request parameter or request header and pass it to the API interface.
The gateway service of the API interface obtains the sign value, then uses the same request parameter timestamp key to splice it into a string, uses the same m5 algorithm to generate another sign, and compares the two sign values. equal.
If the two signs are equal, it is considered a valid request, and the gateway service of the API interface will forward the request to the corresponding business system.
If the two signs are not equal, the gateway service of the API interface will directly return a signature error.
Here comes the question: Why should a timestamp be added to the signature?
Answer: For security reasons, to prevent the same request from being used repeatedly and increase the possibility of the key not being cracked, we must set a reasonable expiration time for each request, such as: 15 minutes .
Such a request is valid within 15 minutes. If it exceeds 15 minutes, the gateway service of the API interface will return an exception prompt indicating that the validity period has expired.
Currently there are two forms of keys used in generating signatures:
One is that both parties agree on a fixed value privateKey.
The other is that the API interface provider gives two values AK/SK, and both parties agree to use SK as the key in the signature. The AK interface caller passes it to the API interface provider as the accessKey in the header, so that the API interface provider can obtain the SK based on the AK and generate a new sgin.
Sometimes, our API interface directly transmits very important data, such as: user’s bank card number, transfer amount, user ID card, etc. If these parameters are It is very dangerous to directly expose the text to the public Internet.
Thus, we need to encrypt the data
.
Currently, the most commonly used method is to use BASE64
for encryption and decryption.
We can splice all the data into a large string according to certain rules, and then add a key
to splice them together.
Then use the Base64 tool class after JDK1.8 for processing. The effect is as follows:
【加密前的数据】www.baidu.com 【加密后的数据】d3d3LmJhaWR1LmNvbQ==复制代码
For security, Base64 can be used to encrypt multiple times.
When the caller of the API interface passes parameters, there is only one parameter data in the body, which is the encrypted data after base64.
The gateway service of the API interface, after receiving the data data, decrypts it according to the key, encryption algorithm, encryption times, etc. predetermined by both parties, and deserializes the parameter data.
In order to further strengthen the security of the API interface and prevent the signature or encryption of the interface from being cracked, the attacker can request the interface on his own server.
Requirement limit requestip
, add ip whitelist
.
Only IP addresses in the whitelist can successfully request the API interface, otherwise no access permission will be returned directly.
The IP whitelist can also be added to the API gateway service.
But it is also necessary to prevent the company's internal application server from being breached. In this case, API interface requests can also be initiated from the internal server.
At this time, you need to add a web firewall, such as: ModSecurity, etc.
If your API interface is called by a third-party platform, this means that the frequency of calls cannot be controlled.
When a third-party platform calls your API interface, if the concurrency is too high, your API service may become unavailable and the interface will hang up directly.
Therefore, current limiting
must be done on the API interface.
There are three current limiting methods:
Limit the current of the requested IP: For example, the same IP, within one minute, the total number of requests to the API interface Number of times
cannot exceed 10,000 times.
Limit the flow of request interfaces: For example, for the same IP, within one minute, the number of requests to the specified API interface
cannot exceed 2,000 times.
Limit the flow of requesting users: For example, the same AK/SK user
can make no more than 10,000 requests to the API interface in one minute. .
我们在实际工作中,可以通过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页面,给第三方平台的用户开通查看权限。这样他们就能在外网查看请求日志了,他们自己也能定位一部分问题。
The third-party platform is very likely to request our interface multiple times in a very short period of time, for example: request twice within 1 second. It is possible that there is a bug in their business system, or the interface call fails to be retried, so our API interface needs to be idempotent
.
That is to say, it is necessary to support the third-party platform to request the API interface multiple times with the same parameters in a very short period of time. The first time the database is requested, new data will be added, but after the second request, the data will not be added. New data is added, but success will also be returned.
The purpose of this is not to generate erroneous data.
In our daily work, we can add unique index
to database
, or save requestId
in redis
and request parameters to ensure interface idempotence.
Friends who are interested in the idempotence of interfaces can read my other article "How to ensure the idempotence of interfaces under high concurrency? ", which has a very detailed introduction.
For the batch interface provided to me, I must limit the number of records requested
.
If too much data is requested, it is easy to cause problems such as APIinterface timeout
, making the API interface unstable.
Normally, it is recommended that the parameters in a request support up to 500 records.
If the user passes in more than 500 records, the interface will directly give a prompt.
It is recommended that this parameter be made configurable and negotiated with the third-party platform in advance to avoid unnecessary problems after going online.
Before going online, we must do a stress test
on the API interface to know the qps
situation of each interface.
So that we can better estimate how many server nodes need to be deployed, which is crucial to the stability of the API interface.
Although the API interface has been limited in current flow before, it is a question mark whether the API interface can actually reach the limit threshold. If no stress testing is performed, there is a great risk.
For example: Your API interface is limited to only 50 requests per second, but the actual API interface can only handle 30 requests, so your API interface will not be able to handle it.
We can use jmeter
or apache benc
to do stress testing on the API interface at work.
The logic of general API interfaces is processed synchronously, and the result is returned immediately after the request is completed.
But sometimes, the business logic in our API interface is very complex, especially some batch interfaces. If the business is processed synchronously, it will take a very long time.
In this case, in order to improve the performance of the API interface, we can change it to asynchronous processing
.
In the API interface, you can send an mq message
and then directly return success. After that, there is a dedicated mq consumer
to asynchronously consume the message and do business logic processing.
The third-party platform can obtain the direct asynchronous processing interface in two ways.
The first way is: we callback
the interface of the third-party platform and inform them of the processing results of the API interface. This is how many payment interfaces work.
The second way is: the third-party platform calls our other API interface for querying status through polling
, and queries the status every once in a while. The parameter passed in is the previous one. The id collection in the API interface.
Sometimes when a third-party platform calls our API interface, part of the data obtained is sensitive data, such as user mobile phone number, bank card number, etc.
If such information is directly retained on the external network through the API interface, it is very unsafe and can easily lead to the leakage of user privacy data.
This requires data desensitization
on some data.
We can replace part of the content with asterisks
in the returned data.
The user’s mobile phone number is as an example: 182****887
.
In this way, even if the data is leaked, only part of it will be leaked, and it will be useless for criminals to get this data.
To be honest, a complete API interface document can reduce a lot of communication costs and save the other party from making many detours when the two parties are doing interface docking.
The interface document needs to contain the following information:
Interface address
Request method, such as: post or get
Introduction to request parameters and fields
Introduction to return values and fields
Return codes and error messages
Encryption or signing example
Full request demo
Additional instructions, such as: opening an IP whitelist.
It is best to unify the naming style of interface and field names in the interface document, for example, use camel case identifier
to name them.
Unify the type and length of fields, for example: the id field uses Long type, and the length is specified as 20. The status field uses int type, with a fixed length of 2, etc.
Uniform time format field, for example: time uses String type, the format is: yyyy-MM-dd HH:mm:ss.
The interface document states the AK/SK and domain name, and asks someone to provide it separately.
Recommended learning: "PHP Video Tutorial"
The above is the detailed content of When designing API interfaces, pay attention to these places!. For more information, please follow other related articles on the PHP Chinese website!