理解HTTP幂等性
基于HTTP协议的Web API是时下最为流行的一种分布式服务提供方式。无论是在大型互联网应用还是企业级架构中,我们都见到了越来越多的SOA或RESTful的Web API。为什么Web API如此流行呢?我认为很大程度上应归功于简单有效的HTTP协议。HTTP协议是一种分布式的面向资源的网络应用层协议,无论是服务器端提供Web服务,还是客户端消费Web服务都非常简单。再加上浏览器、Javascript、AJAX、JSON以及HTML5等技术和工具的发展,互联网应用架构设计表现出了从传统的PHP、JSP、ASP.NET等服务器端动态网页向Web API + RIA(富互联网应用)过渡的趋势。Web API专注于提供业务服务,RIA专注于用户界面和交互设计,从此两个领域的分工更加明晰。在这种趋势下,Web API设计将成为服务器端程序员的必修课。然而,正如简单的Java语言并不意味着高质量的Java程序,简单的HTTP协议也不意味着高质量的Web API。要想设计出高质量的Web API,还需要深入理解分布式系统及HTTP协议的特性。
幂等性定义
本文所要探讨的正是HTTP协议涉及到的一种重要性质:幂等性(Idempotence)。在HTTP/1.1规范中幂等性的定义是:
Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request.
从定义上看,HTTP方法的幂等性是指一次和多次请求某一个资源应该具有同样的副作用。幂等性属于语义范畴,正如编译器只能帮助检查语法错误一样,HTTP规范也没有办法通过消息格式等语法手段来定义它,这可能是它不太受到重视的原因之一。但实际上,幂等性是分布式系统设计中十分重要的概念,而HTTP的分布式本质也决定了它在HTTP中具有重要地位。
分布式事务 vs 幂等设计
为什么需要幂等性呢?我们先从一个例子说起,假设有一个从账户取钱的远程API(可以是HTTP的,也可以不是),我们暂时用类函数的方式记为:
bool withdraw(account_id, amount)
withdraw的语义是从account_id对应的账户中扣除amount数额的钱;如果扣除成功则返回true,账户余额减少amount;如果扣除失败则返回false,账户余额不变。值得注意的是:和本地环境相比,我们不能轻易假设分布式环境的可靠性。一种典型的情况是withdraw请求已经被服务器端正确处理,但服务器端的返回结果由于网络等原因被掉丢了,导致客户端无法得知处理结果。如果是在网页上,一些不恰当的设计可能会使用户认为上一次操作失败了,然后刷新页面,这就导致了withdraw被调用两次,账户也被多扣了一次钱。如图1所示:
图1
这个问题的解决方案一是采用分布式事务,通过引入支持分布式事务的中间件来保证withdraw功能的事务性。分布式事务的优点是对于调用者很简单,复杂性都交给了中间件来管理。缺点则是一方面架构太重量级,容易被绑在特定的中间件上,不利于异构系统的集成;另一方面分布式事务虽然能保证事务的ACID性质,而但却无法提供性能和可用性的保证。
另一种更轻量级的解决方案是幂等设计。我们可以通过一些技巧把withdraw变成幂等的,比如:
int create_ticket()
bool idempotent_withdraw(ticket_id, account_id, amount)
create_ticket的语义是获取一个服务器端生成的唯一的处理号ticket_id,它将用于标识后续的操作。idempotent_withdraw和withdraw的区别在于关联了一个ticket_id,一个ticket_id表示的操作至多只会被处理一次,每次调用都将返回第一次调用时的处理结果。这样,idempotent_withdraw就符合幂等性了,客户端就可以放心地多次调用。
基于幂等性的解决方案中一个完整的取钱流程被分解成了两个步骤:1.调用create_ticket()获取ticket_id;2.调用idempotent_withdraw(ticket_id, account_id, amount)。虽然create_ticket不是幂等的,但在这种设计下,它对系统状态的影响可以忽略,加上idempotent_withdraw是幂等的,所以任何一步由于网络等原因失败或超时,客户端都可以重试,直到获得结果。如图2所示:
图2
和分布式事务相比,幂等设计的优势在于它的轻量级,容易适应异构环境,以及性能和可用性方面。在某些性能要求比较高的应用,幂等设计往往是唯一的选择。
HTTP的幂等性
HTTP协议本身是一种面向资源的应用层协议,但对HTTP协议的使用实际上存在着两种不同的方式:一种是RESTful的,它把HTTP当成应用层协议,比较忠实地遵守了HTTP协议的各种规定;另一种是SOA的,它并没有完全把HTTP当成应用层协议,而是把HTTP协议作为了传输层协议,然后在HTTP之上建立了自己的应用层协议。本文所讨论的HTTP幂等性主要针对RESTful风格的,不过正如上一节所看到的那样,幂等性并不属于特定的协议,它是分布式系统的一种特性;所以,不论是SOA还是RESTful的Web API设计都应该考虑幂等性。下面将介绍HTTP GET、DELETE、PUT、POST四种主要方法的语义和幂等性。
HTTP GET方法用于获取资源,不应有副作用,所以是幂等的。比如:GET http://www.bank.com/account/123456,不会改变资源的状态,不论调用一次还是N次都没有副作用。请注意,这里强调的是一次和N次具有相同的副作用,而不是每次GET的结果相同。GET http://www.news.com/latest-news这个HTTP请求可能会每次得到不同的结果,但它本身并没有产生任何副作用,因而是满足幂等性的。
HTTP DELETE方法用于删除资源,有副作用,但它应该满足幂等性。比如:DELETE http://www.forum.com/article/4231,调用一次和N次对系统产生的副作用是相同的,即删掉id为4231的帖子;因此,调用者可以多次调用或刷新页面而不必担心引起错误。
比较容易混淆的是HTTP POST和PUT。POST和PUT的区别容易被简单地误认为“POST表示创建资源,PUT表示更新资源”;而实际上,二者均可用于创建资源,更为本质的差别是在幂等性方面。在HTTP规范中对POST和PUT是这样定义的:
The POST method is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line ...... If a resource has been created on the origin server, the response SHOULD be 201 (Created) and contain an entity which describes the status of the request and refers to the new resource, and a Location header.
The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server. If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI.
POST所对应的URI并非创建的资源本身,而是资源的接收者。比如:POST http://www.forum.com/articles的语义是在http://www.forum.com/articles下创建一篇帖子,HTTP响应中应包含帖子的创建状态以及帖子的URI。两次相同的POST请求会在服务器端创建两份资源,它们具有不同的URI;所以,POST方法不具备幂等性。而PUT所对应的URI是要创建或更新的资源本身。比如:PUT http://www.forum/articles/4231的语义是创建或更新ID为4231的帖子。对同一URI进行多次PUT的副作用和一次PUT是相同的;因此,PUT方法具有幂等性。
在介绍了几种操作的语义和幂等性之后,我们来看看如何通过Web API的形式实现前面所提到的取款功能。很简单,用POST /tickets来实现create_ticket;用PUT /accounts/account_id/ticket_id&amount=xxx来实现idempotent_withdraw。值得注意的是严格来讲amount参数不应该作为URI的一部分,真正的URI应该是/accounts/account_id/ticket_id,而amount应该放在请求的body中。这种模式可以应用于很多场合,比如:论坛网站中防止意外的重复发帖。
总结
上面简单介绍了幂等性的概念,用幂等设计取代分布式事务的方法,以及HTTP主要方法的语义和幂等性特征。其实,如果要追根溯源,幂等性是数学中的一个概念,表达的是N次变换与1次变换的结果相同,有兴趣的读者可以从Wikipedia上进一步了解。
参考
RFC 2616, Hypertext Transfer Protocol -- HTTP/1.1, Method Definitions
The Importance of Idempotence
Stackoverflow - PUT vs POST in REST
相关推荐
VB控制计算机并口示例(含完整可以运行源代码) 可以通过并口直接控制MCU,做SW控制不错,关键还可以学习并口硬件控制学习。含详细源代码哦
python毕业设计基于PyTorch的手语识别系统源码+数据集(完整项目代码),本资源中的源码都是经过本地编译过可运行的,评审分达到98分,资源项目的难度比较适中,内容都是经过助教老师审定过的能够满足学习、毕业设计、期末大作业和课程设计使用需求,如果有需要的话可以放心下载使用。 python毕业设计基于PyTorch的手语识别系统源码+数据集(完整项目代码)python毕业设计基于PyTorch的手语识别系统源码+数据集(完整项目代码)python毕业设计基于PyTorch的手语识别系统源码+数据集(完整项目代码)python毕业设计基于PyTorch的手语识别系统源码+数据集(完整项目代码)python毕业设计基于PyTorch的手语识别系统源码+数据集(完整项目代码)python毕业设计基于PyTorch的手语识别系统源码+数据集(完整项目代码)python毕业设计基于PyTorch的手语识别系统源码+数据集(完整项目代码)python毕业设计基于PyTorch的手语识别系统源码+数据集(完整项目代码)python毕业设计基于PyTorch的手语识别系统源码+数据集(完整项目代
基于Unet的树种分别识别模型
精选毕设项目-富文本解析,折线图,MD5,bluebird
《图书管理系统(基于ASP .NET)》是一款专为学习者设计的应用程序,旨在提供一个全面的图书管理平台。系统的设计采用ASP .NET技术,这是一款由微软开发的用于构建动态网站、web应用和web服务的强大工具。ASP .NET框架以其高效、安全和易于维护的特点,深受开发者的喜爱。 该系统包含了多个核心模块,这些模块覆盖了图书管理的主要功能。有图书录入模块,它允许管理员录入图书的基本信息,如书名、作者、出版社、ISBN号、分类等。图书查询模块提供给用户方便快捷的搜索功能,用户可以根据书名、作者、关键词等条件进行检索。此外,借阅与归还模块确保图书的流通管理,记录图书的借阅状态,提醒用户按时归还,并处理超期罚款等事务。 系统还具备用户管理模块,允许用户注册、登录、修改个人信息。对于权限管理,后台有专门的管理员角色,他们可以对用户进行操作,如分配权限、冻结或解冻账户。同时,系统的统计分析模块能够生成各类报表,如图书借阅量、热门书籍、用户活跃度等,这些数据对于图书馆运营决策有着重要参考价值。 在。内容来源于网络分享,如有侵权请联系我删除。另外如果没有积分的同学需要下载,请私信我。
精选毕设项目-查拼音
精选毕设项目-音乐在线歌词搜索
本专刊的主要目的是帮助初学者系统化和结构化地掌握会计知识。我们采用思维导图的形式,将复杂的会计概念和流程进行有效的简化,旨在让学习者能够更清晰地理解这些内容,并增强记忆效果。通过视觉化的方式,读者不仅能够感受到会计知识的关联性,还能轻松掌握关键点,提升学习效率。无论是在学习新知识还是复习旧知识时,这种方法都能够为学习者提供极大的便利和帮助。
配网两阶段鲁棒优化调度模型 关键词:两阶段鲁棒优化,CCG算法,储能 仿真算例采用33节点,采用matlab+yalmip+cplex编写,两阶段模型采用CCG算法求解。 模型中一阶段变量主要包括01变量和无功优化变量,核心变量主要存在于二阶段,因此在叠加二阶段变量优化过程中更容易得到最优解,所以有限次迭代即得到收敛的结果。 模型以网损为目标,包括功率平衡、网络潮流、电压电流、蓄电池出力以及无功设备出力等约束。 复现《两阶段鲁棒优化的主动配电网动态无功优化》-熊壮壮,具体内容可自行下载了解。
1..1行列式的定义.ppt
精选毕设项目-地图定位
MMC整流器平均值模型simulink仿真,19电平,采用交流电流内环,直流电压外环控制,双二阶广义积分器锁相环,PI解耦环流抑制器,调制方式为最近电平逼近调制,完美运行。 波形一二为直流侧电压电流,波形三四分别为主控制器及环流抑制器输出调制信号。
Spring Boot是Spring框架的一个模块,它简化了基于Spring应用程序的创建和部署过程。Spring Boot提供了快速启动Spring应用程序的能力,通过自动配置、微服务支持和独立运行的特性,使得开发者能够专注于业务逻辑,而不是配置细节。Spring Boot的核心思想是约定优于配置,它通过自动配置机制,根据项目中添加的依赖自动配置Spring应用。这大大减少了配置文件的编写,提高了开发效率。Spring Boot还支持嵌入式服务器,如Tomcat、Jetty和Undertow,使得开发者无需部署WAR文件到外部服务器即可运行Spring应用。 Java是一种广泛使用的高级编程语言,由Sun Microsystems公司(现为Oracle公司的一部分)在1995年首次发布。Java以其“编写一次,到处运行”(WORA)的特性而闻名,这一特性得益于Java虚拟机(JVM)的使用,它允许Java程序在任何安装了相应JVM的平台上运行,而无需重新编译。Java语言设计之初就是为了跨平台,同时具备面向对象、并发、安全和健壮性等特点。 Java语言广泛应用于企业级应用、移动应用、桌面应用、游戏开发、云计算和物联网等领域。它的语法结构清晰,易于学习和使用,同时提供了丰富的API库,支持多种编程范式,包括面向对象、命令式、函数式和并发编程。Java的强类型系统和自动内存管理减少了程序错误和内存泄漏的风险。随着Java的不断更新和发展,它已经成为一个成熟的生态系统,拥有庞大的开发者社区和持续的技术创新。Java 8引入了Lambda表达式,进一步简化了并发编程和函数式编程的实现。Java 9及以后的版本继续在模块化、性能和安全性方面进行改进,确保Java语言能够适应不断变化的技术需求和市场趋势。 MySQL是一个关系型数据库管理系统(RDBMS),它基于结构化查询语言(SQL)来管理和存储数据。MySQL由瑞典MySQL AB公司开发,并于2008年被Sun Microsystems收购,随后在2010年,Oracle公司收购了Sun Microsystems,从而获得了MySQL的所有权。MySQL以其高性能、可靠性和易用性而闻名,它提供了多种特性来满足不同规模应用程序的需求。作为一个开源解决方案,MySQL拥有一个活跃的社区,不断为其发展和改进做出贡献。它的多线程功能允许同时处理多个查询,而其优化器则可以高效地执行复杂的查询操作。 随着互联网和Web应用的快速发展,MySQL已成为许多开发者和公司的首选数据库之一。它的可扩展性和灵活性使其能够处理从小规模应用到大规模企业级应用的各种需求。通过各种存储引擎,MySQL能够适应不同的数据存储和检索需求,从而为用户提供了高度的定制性和性能优化的可能性。
这是一种全屏轮播风格的特效,使用HTML、CSS和Javript编写。轮播图包含多张图片和对应的文本介绍,通过自动滑动和手动切换两种方式,展示出不同的内容。该轮播图在网页头部或者特定板块上使用,能够为用户提供直观的视觉体验和丰富的内容呈现。而且,该轮播图可以灵活地设置大小、位置、动画等属性,便于根据实际需求进行个性化定制。
精选毕设项目-图片预览带后端
精选毕设项目-番茄时钟
精选毕设项目-简单的商城小应用
精选毕设项目-仿zcool站酷
精选毕设项目-录音机
南京理工大学毕业论文overleaf LaTex模板,按照我个人的写作需求修改后的版本