《 Restful Web Services 》读书笔记
第六章 Designing Read/Write Resource-Oriented Services
本章作者设计了一个可读写的面向资源服务。
作者扩展上一章的地图服务, 想设计一个用户自定义地点的地图服务来进一步说明ROA的设计。 作者把用户帐户作为资源,有两点考虑。第一, 如果和一般的web应用一样,注册一个用户,必须重载post来模拟非安全的操作。 第二, 这样会带来一些新特性,用户可以不必登陆网站来注册用户。
认证,授权,保密和信任
因为暴露了用户资源,当有人发来http请求,这样必然需要判断这个请求是谁发出来的,这个时候就需要认证。作者这里简单描述了这些概念:
当web客户端发出一个请求时,它将在Authorization报头里附上一些证书(credentials)。在服务收到该请求后,它会通过检查这些证书来确定客户端是否代表某一特定帐户(认证),以及该用户是否被允许做它所请求的操作(授权)。标准的认证方案常用的有:HTTP基本认证,HTTP摘要认证(HTTP Digest)和WSSE认证。我们还需要考虑保密性,用户A的私有数据不应该被其他用户访问,如何防止不被截获呢?可以用SSL对HTTP进行加密。关于用户信任问题,HTTP标准并没有给出解决方法。
创建可读写资源的步骤:
1. 规划数据集
2. 把数据集划分为资源
对于其中的每种资源:
3. 用URI为该资源命名
4. 暴露一个统一接口的子集
5. 设计来自客户端的表示
6. 设计发给客户端的表示
7. 用超链接和表单把该资源与已有资源联系起来
8. 考虑有哪些典型的事件经过
9. 考虑可能出现哪些错误情况
比上一章讲的步骤多了第四步和第五步。
将用户帐户作为资源的设计过程:
一 规划数据集:
显然只有用户名和密码(为了简单说明,不包含用户的其他信息,比如email和地址等)
二 把数据集划分为资源:
按第五章的分类, 用户帐户属于第二类资源。服务通过这些资源来暴露背后的相关对象。
三 用URI为资源命名
https:// maps.example.com/user/{user-name}
四 暴露一个统一接口的子集
通过回答以下问题来决定暴露统一接口的哪些子集:
客户端将创建这种新资源吗?
在本章的例子里的答案就是,当然了, 用户需要注册进入系统。
当客户端创建这种新资源时,谁负责决定这个新资源的URI?客户端还是服务端 ?
这个URI是由客户端负责的, 因为上面的步骤中uri表示里user-name是客户来写的。
通过上面的两个问题, 得到,要创建用户资源,客户端就向该帐户的uri发送put请求,因为uri是由客户端负责决定的。
客户端将修改这些资源吗?
起码用户密码是应该被客户修改的。
客户端将删除这些资源吗 ?
当帐户不用的时候,允许用户将其删除
客户端将获取这种资源的表示吗?
是的。 也许可以用它来检查某个用户名是否已被占用。
五 设计来自客户端的表示
也就是说,客户端应该如何来创建一个用户帐户。
此时用户名已经作为uir里的作用域信息了,密码放哪里 ?
客户端会把密码作为资源表示放在实体主体里发送过去。客户端应该采用什么格式来表达新的资源状态。假如资源状态比较复杂,那么采用服务器发给客户端时采用的格式比较好。客户端通过GET请求从服务端得到一个表示,然后修改其表示,在通过PUT请求发回给客户端。作者采用表单编码格式(媒体类型application/x-www-form-urlencoded)来作为表示格式。
六 设计发给客户端的表示
要注意的是,这里的密码, 是不能发到客户端的。 所以需要根据具体的情况,来设计发给客户端的表示。
七 把该资源与现有资源链接起来
作者举了两个例子, 我只说一个。 上一章里作者为地图服务定义了很多资源,比如星球列表。 如何链接呢, 对于未注册的用户,当他get回一个星球列表资源来,可以看到超媒体表示-注册用户的链接。
八 会由哪些典型事件经过
此时可能会有客户端向/user/blackanger发送put请求,将发生什么 ?我需要决定,为返回的响应设置什么响应代码,应提供什么http报头和实体主体,该请求如何影响资源状态。
九 可能出现哪些错误情况
考虑到一些可能出现的错误情况,设置响应代码。例子看书P156
自定义地点
于这个资源, 又要重复一遍上述的设计步骤。 但是这个资源类型和用户帐号资源有不同,这是一个从属资源。可以去看书P157,这里不做记录。
下一章,也就是第七章,有一个具体的实践, 继续重复上述步骤,不过起码可以通过代码看到一个具体到服务的实现了。
我来说两句:
看完本章作者把用户帐户作为一个资源, 结合以往几章的种种, 不禁要想,登陆这个操作,并不属于HTTP统一接口里的方法,按面向资源的设计,登陆这个要抽象为一个对象,也就是登陆也就是一个资源了。 让我们来看看Rails插件 restful_authentication就是遵循了这个原则。
有一个session_controller.rb, rails里controller表示的是资源(我发明的土话)。用户登陆, session里保存用户状态,那么相当于给sessoin这个资源里创建一个子资源。 只要往这里发送put请求就行了。来看看routes设置:
map.logout '/logout', :controller => 'sessions', :action => 'destroy'
map.login '/login', :controller => 'sessions', :action => ' new'
登陆就是new一个session对象, 注销就是把这个对象删除了。很自然明了。
让我们来看看生成的表单:
<form method= "post" action= "/session">
... ...
</form>
这里的http方法应该是PUT的呀, 可是为什么会是POST呢?引用DHH的话来说明:
“这个表单的action不是一个常规的POST方法,而是一个PUT。这里展示的是这个操作应该的模样。如果HTML表单支持PUT方法的话,我们本该这样写来着。很不幸,事实并非如此(HTML表单不支持PUT action),所以我们只能用POST来伪造一个PUT。在Rails中,当你这样写的时候,产生出来的表单里包含了一个隐藏的域,称为 underscored method(下划线方法),这个下划线方法会去调用真正干事的那个方法。我们这么做就能让Rails相信,这个POST实际上是个PUT”
下一章,也就是第七章,有一个具体的Rails实践, 继续重复上述步骤,不过起码可以通过代码看到一个具体到服务的实现了。
to be continued ... ...