API 设计中的幂等性

2025-06-05

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);
        });
    });
}
Enter fullscreen mode Exit fullscreen mode

这没问题,它会返回值,但如果发生网络错误会发生什么?如果能自动重试就好了。

这就是幂等性的作用所在。网络错误是双向的。正如客户端的数据包在传输到服务器的路径上可能被中断一样,响应也可能在返回客户端的路径上被中断,从而触发自动重试。因此,你的 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
    }
}
Enter fullscreen mode Exit fullscreen mode

感谢阅读!

有问题吗?想聊聊《曼达洛人》吗?快来Twitter上关注我吧!

文章来源:https://dev.to/gladdstone/idempotency-in-api-design-36ci
PREV
DevOps 工程师的 20 个生活小窍门
NEXT
追踪 Node.js 中的高内存使用情况