NO END FOR LEARNING

Writing blog if you feel tired | 学海无涯 苦写博客

理解设计RESTful API - 资源、表述和HTTP协议语义

| Comments

什么是资源?什么是表述?

就本质而言,任何足够重要并被引用的事物都可以是资源。如果你的用户“想要建立指向它的超文本链接,指出或者反对关于它的断言,获取或者缓存它的表述,共另外的表述引用它的全部或者部分,给它增加注释信息,或者对它执行某些操作”,(源自《万维网的架构》),你都应该将它定义为资源。

每个资源必须拥有URL,在web上,我们使用URL来为每个资源提供一个全球唯一的地址,将一个事物赋以URL,它就会成为一个资源。

石榴可以是一个资源,但是你不可能通过互联网传输它,数据库中的一条记录可以是一个资源,并且可以通过互联网传输。

当客户端对一个资源发起一个Get请求的时候,服务器会以一种有效的方式提供一个采集了资源信息的文档作为回应。这种资源信息的文档就是一种表述,一种以机器可读的方式对资源当前的状态进行说明。

资源有多重表述

一个资源可以有多种表述。比如,有的资源可以有整体概括性的表述,也可以有面面俱到的详细表述,又或者可能以JSON格式或者XML格式来表述同一个资源。

约束 - HTTP协议语义

尽管任何事物都可以成为一个资源,但是客户端并不能随心所欲地对资源进行任意的操作。所能进行的操作是有规定的。在一个RESTful系统里,客户端和服务器端只能通过相互发送遵循预定义协议的消息来进行交互。在Web API的世界里,该协议就是HTTP。

在设计Web API时,严格遵守HTTP协议语义是设计好的API的重要基础。

GET请求

客户端通过发送Get请求来获取某个URL所标示的资源的表述。Get被定义为安全的HTTP方法。它仅仅是对信息的一次请求。向服务器发送一条Get请求对资源的影响应该和没有发送一样。

DELETE请求

发送DELETE请求,客户端希望服务器将资源销毁,并且以后再也不会跳到它。当Get请求再次访问一个已经销毁的资源,服务器应该返回错误响应码,比如404(Not Found)。Delete不是一个安全的方法,它会改变资源的状态,但是DELETE方法有另外一个很重要的属性,就是幂等性。当你发送一个DELETE请求后,资源就永久性的消失了,即便之后,再次发送相同的DELETE请求,也许你会收到404的错误码,但是第二次发送后和第一次发送后,资源的状态是一致的,仍然不存在。

幂等性是一个很重要的特性,因为互联网的不稳定性,假设发送的一个Delete请求,因为连接超时,你并没有收到响应,所以你无法知道发送的Delete请求是否顺利完成,这时你也许会发送第二次Delete请求。幂等性保证了执行两次Delete请求并不会比执行一次Delete请求给资源带来更多的影响。

POST-to-Append请求

为什么是Post-to-Append而不是Post呢?因为Post方法可以做两件事情,第一件事情就是Post-to-Append,第二件事情叫做overloaded post。我们先看POST-to-Append,向某个资源发送一条Post请求用以在该资源的下一级中创建新的资源,当客户端发送一个POST-to-Append请求时,它会在请求的实体消息体中添加所希望创建的资源的表述信息并发给服务器。Post方法既不安全也不幂等,如果发送多次Post请求,就会创建多个资源。

PUT请求

Put请求用于修改资源的状态。客户端一般会通过Get请求获取表述,然后对其进行修改,最后再将修改后的资源表述作为PUT请求的负载数据发送回去。PUT请求也是幂等的,无论发送多少次PUT请求,结果都和第一次发送PUT请求一样。


以上4种请求,我们最常见也是使用最频繁的请求。接下来要介绍的请求,虽然见的不多,但是当你了解后,你会觉得它非常有用。

PATCH请求

表述的信息量可能非常大。虽然,我们可以使用PUT请求来修改资源,但是如果只想修改资源状态的部分,或者说很少一部分,才PUT就会造成极大的资源浪费,这对于移动应用所使用的Web API设计是非常重要的。和将完整信息发送过去的PUT方法不同,PATCH方法将一个“diff”的表述放在请求的负载数据中发送给服务器。

HEAD请求

Head方法是和Get方法一样的安全方法。服务器应该和处理Get方法一样除了Head方法,但是Head方法不需要发送实体消息,只需要发送HTTP状态码和报头。

OPTIONS请求

OPTIONS是HTTP的原生探索机制。一个OPTIONS请求的返回结果包含一个HTTP Allow报头,这个报头展示了这个资源所支持的所有HTTP方法。

肮脏的Overloaded POST请求

POST不仅仅被用于创建新的资源,在用浏览器上网的时候,POST也被用于传输任何形式的变化,它将PUT、DELETE、PATCH、LINK和UNLINK所有的方法混合成一个方法。

比如,在页面有一个表单对用户的基本信息进行修改,它是一个POST请求,但是从语义上,它更像是一个PUT,但这完全是合法的,任何数据作为POST请求的一部分发出去,不论是出于什么目的,这都是合法的。这导致POST请求没有任何语义。由于重载后的POST请求可以用来完成任何事情,所以这种POST方法既不安全也不幂等。


好的API不应该依靠文档来维护它的使用方式,就好像是优秀的代码,不需要注释来考诉你它是干什么,合理的协议语义的使用会帮助API实现基本的自我描述,虽然这还远远不够,但它最起码是互联网上大家都遵守的约束。

参考资料:
1. RESTful Web AIPs

《Linux就是这个范儿》读书笔记(一) - 理解Linux用户和用户组

| Comments

理解什么是多用户多任务分时操作系统

“将大型电脑的珍贵时间资源适当的分配到所有使用者身上,让所有使用者都有独占整部机器的感觉,这是当时计算机先驱提出的分时系统的概念。依据这个想法,通用电气、麻省理工学院和贝尔实验室联手启动Multics项目,这是在当时看着最靠谱的分时系统概念。但是由于太“靠谱”了(真正的多用户多任务分时操作系统),在当时的技术条件下去完成它实在是吃力,所以最终的命运很悲惨。但是有两个游戏爱好者,Multics的成员Ken和Dennis为了能够有电脑玩游戏,决定自己给一台闲置的电脑写个操作系统,于是 — 一个实用的多用户多任务分时操作系统就诞生了。” —-《Linux就是这个范》

我们所熟知的Windows、Linux、Mac OS X等都是多用户多任务分时操作系统。最显著的特点就是可以让多个人使用同一台电脑而不能互相窥探对方的秘密(多用户)。当你使用电脑时,可以边放音乐,边聊QQ,边浏览网页(多任务)。分时就像之前的定义那样,将电脑的时间资源适当的分配给所有的使用者身上,如果将使用者抽象,它不仅仅代表“人”,可以代表任何使用电脑时间资源的任务,在这样的理解下,分时就成为了多用户和多任务的基础。

澡堂文化 - 多用户

Linux中的用户管理是管理用户的等级和对文件的访问权限。

用户等级只有两个root和非root用户。root用户拥有至高无上的权利,用户名就是root,相当于Windows中的Administrator,但幸运的是root用户只有一个。root用户通过文件严格控制着非root用户的访问权限。

在《Linux就是这个范》这本书中,作者将这种管理方式形象的描述为“澡堂子模型”。root用户就是澡堂子的服务生,每个来澡堂子的人,服务生都会给分配一个号码牌,就像root用户给非root用户分配账号。每个号码牌上都有一个钥匙,可以打开对应的柜子。

而每个非root用户一般会拥有自己的文件目录(某些不会,它们可能是执行特殊任务的用户,不需要自己的文件目录),目录路径一般是/home/[username],这就是,每个非root用户的目录就对应着每个来澡堂中的柜子。

用户权限(不同的职业)

在使用Linux的时候,经常会遇到无法对文件读写,或者执行,因为当前登录账号的权限不够。因此,会给予一种错觉,那就是账号分为不同的权限级别,另一个账号可以访问,因为它比当前登录账号权限更高。

但这其实是一种错误的理解,前面已经提到,Linux中用户等级只有两个,root和非root,除了root用户拥有至高无上的权利外,其他用户都是一样的渣渣。

导致这种错觉的原因,是因为还有一个用户组的概念(职业)。

一个用户可以属于多个用户组,就像一个人可以身兼多职一样。由于用户组能够在更高的层面来抽象用户所能够访问文件的数量,因此结合不同的用户组,就能给每个用户构建出独一无二的文件访问列表。

用户和用户组管理

用户和用户组信息分别存放在etc/passwd和etc/group中,Linux系统为用户和用户组文件的CRUD操作提供了一些基本命令,这些命令的作用就是对etc/passwd和etc/group两个文件的文件内容进行增删改,然后,外加一个etc/shadow文件来管理密码,就实现了对用户和用户组的管理。

关于什么样的命令来管理用户和用户组,这里不做更多介绍,可以参考其他资料。

神秘的sudo-假借身份

安装软件是使用Linux操作系统最常见的操作。但Linux中的用户除了root就是普通用户,而普通用户的权限非常低,就连向系统中安装软件的权利都没有。很多时候系统管理员为了能够让普通用户具备一点root的特权,就赋给普通用户一个称为sudo的特权。

普通用户一旦拥有sudo的特权,几乎就可以胡作非为,但需要付出一点代价,需要在将要执行的命令前加上sudo作为前缀,同时被系统提示输入当前用户的密码。这样做的好处是防止不怀好意的进行不安全的操作。因为你不是root用户,所以如果有恶意软件要使用sudo进行操作,此时就会被需要输入密码,这种无缘无故需要输入密码的行为一定会被你发现。

不同的Linux发行版本,可能一般的非root用户不会立即拥有sudo特权。所以这时就需要自己去给某个用户赋予sudo特权,方法是修改/etc/sudoers这个文件。至于文件里的内容长什么样,这里也不过多介绍,可以参考其他资料。

每次都要sudo,好麻烦,干脆su

要使用sudo特权,必须每次在命令前加上sudo,这样对管理Linux系统不太方便。su命令可以临时切换用户,默认是切换到root用户。

切换用户需要输入目标用户的密码,切换到root用户就需要root用户的密码。

我是谁和我到底是谁

要知道当前用户是谁,有三条命令可以用,whoami,who am i和who。第一个命令和后两条命令有本质区别,这里要引入实际用户(UID)和有效用户(EUID)的概念。

实际用户就是指用户登录时所使用的用户,整个登录会话中,实际用户不会改变;有效用户是指当前执行操作的用户,该用户可以通过su切换,决定了权限的高低。

whoami查看的是有效用户,而who和who am i可以查看实际用户。

参考资料:
1.Linux就是这个范儿