API 设计中的幂等性
API 赋予了 Web 开发者强大的力量。它是一项万物皆可使用的技术。它包围着我们,渗透着我们。它将 Web 紧密联系在一起。
现代网络由 API 驱动,不仅要会编写 API,还要能正确构建 API,这绝对是一项至关重要的技能。
一个设计良好的 RESTful API 应该具备以下几点:
- 有据可查
- 围绕其提供的资源进行设计
- 使用无状态请求模型——这意味着您不应该在请求之间存储任何数据。每个请求都应该是独立的操作。
但最重要的是,可靠性和安全性至关重要。不可靠的 API 是无用的 API。衡量一个 API 好坏的标准往往不是技术本身,而是人们能够用它构建什么。重要的是,不要用不可靠的 API 吓跑潜在用户。
那么,可靠性和安全性在架构层面是什么样的?
幂等性和安全性
RESTful API 根据客户端发出的 HTTP 请求提供信息。这些 HTTP 请求具有一个称为“安全性”的属性,而理解安全性是第一步。
安全的 HTTP 请求:
获取 - 是
放置 - 否
发布 - 否
删除 - 否
修补 - 否
如果 HTTP 请求类型在调用时不会改变数据,则该请求类型被认为是“安全的”。当然,GET 请求也是一种“安全”的请求类型,因此它们从一开始就被认为是幂等的。
但这并没有回答幂等性的问题。幂等性是指 API 方法一旦被调用一次,就不会在任何后续的相同请求中进一步修改服务器状态。
好多啊。这是什么意思呢?想象一下一个数学函数。
f(x) = x^2 + 2
如果 x = 5,那么 f(x) 始终等于 27。如果再次执行此操作,f(x) 仍然等于 27,因为输入数据没有改变。同样,如果用户向服务器发送一个从数据库中删除一行的请求,然后再次发送相同的请求,他们每次都应该得到相同的“行已成功删除”的结果,但状态只会改变一次。
执行
从客户端来看,对 API 的 POST 请求可能如下所示:
import axios from ‘axios’;
static callAction(url, parameters = {}) {
return new Promise((resolve, reject) => {
return axios.post(API_URL + url, parameters).then(x => {
resolve(x.data.data);
});
});
}
这没问题,它会返回值,但如果发生网络错误会发生什么?如果能自动重试就好了。
这就是幂等性的作用所在。网络错误是双向的。正如客户端的数据包在传输到服务器的路径上可能被中断一样,响应也可能在返回客户端的路径上被中断,从而触发自动重试。因此,你的 API 方法必须做好准备来处理这种可能发生的情况。
幸运的是,实现幂等性非常简单。只需附加我们的好朋友 GUID,即全局唯一标识符(也称为 UUID,但我喜欢称之为“gwid”)。这个 128 位的数字可以由客户端生成,并作为标头值附加到请求中。
通过 API 进行身份验证后,处理起来就简单多了。只需将 GUID 和服务器响应保存一段指定的时间即可(确保这些数据会自动删除,否则会造成相当严重的数据膨胀)。
一旦完成,我们所要做的就是将我们的 callAction 函数放在循环中:
async function callPost() {
let remainingAttempts = 3;
let exceptions = []
try {
while(remainingAttempts > 0) {
await callAction(url, parameters);
remainingAttempts--;
}
} catch(e) {
exceptions.add(e);
} finally {
// this is where you handle the exception, whether it’s logging
// to the console, etc
}
}
感谢阅读!
有问题吗?想聊聊《曼达洛人》吗?快来Twitter上关注我吧!
文章来源:https://dev.to/gladdstone/idempotency-in-api-design-36ci