- 论坛徽章:
- 2
|
回复 44# starwing83
关于JS。 我也没时间去看。。。 只是现在有Lutz顶着于是我就没压力了。。。
关于那两点,我觉得后一句改成: 所有资源都都可以用统一的动词 — GET,HEAD,PUT,DELETE,POST,OPTIONS —去操作。 更合适一些。
没有findItem和findItems,findItemsWhenMatch等不同的动词, 而是用资源来代表单一对象GET /post/ID,集合对象 GET /post,算法(filter) GET /post?after=yesterday 等等。
至于资源是否支持那是资源说了算。 可以用OPTIONS 查询, 可以返回405并给出Allowed, 可以返回404代表这个资源根本不存在。
关于state。 以ftp服务和一个支持上传删除的http文件服务器作为对比。
服务器上肯定是有状态的 —— 目前有哪些文件。 这个状态也是可以改变的 —— 同上传和删除。
RWS里把这个叫做server state。
ftp连接后,可以认证、改变当前目录,列出当前目录,列出当前目录里的文件,下载/上传/重命名/删除文件,创建删除目录等等。
后面那些命令都与认证已经当前目录这两个状态有关。这两个状态会保持到连接断开为止。
而http协议是无状态的。每一个请求都必须包含认证和打算操作的文件的全路径这两个状态,服务器才有足够的信息来完成这个请求。
RWS里把这个叫做application state。 REST api的消费者(application)的状态。
REST application每次都必须把自己的state传递给server,让server有足够的信息完成请求。 这个请求可能会影响server state(unsafe methods)也可能不会(safe methods)。
假设这样实现一个支持匿名用户操作的http文件服务器:
1. GET /files/path/to。 如果 /path/to 是一个文件,就在header里放置相应的content-type,content-length,并且将文件内容放到body里作为响应。 而如果是一个目录,就返回405 Method Not Allowed。
同样还可以通过HEAD查询文件的元信息而并不下载文件。
这两种请求必须将application state —— /path/to 传递给服务器。 但不会影响服务器的状态。
2. PUT /files/path/to 。 上传文件。 如果该路径是一个目录就405 Method Not Allowed。
3. PUT /files/path/to/ 。 创建目录。 如果该路径是一个文件就405 Method Not Allowed。
4. DELETE /files/path/to 。 删除文件或目录。
后面几个如果成功都会影响server state。
问题是这样的api即使是curl消费起来都很困难。。。 至少得有ls功能吧?
于是GET /files/path/to 如果是目录的话, 就可以给出这个目录下的文件和子目录的链接。 于是curl或者浏览器就知道存在哪些资源(文件)以及怎么转换到另一个application state去产生相应的request。
浏览器进入一个目录之后地址栏就会有相应的改变,以显示出当前的application state的一部分。 展示出的链接都是可以转换到的其他的application state。
同时还可以继续带上form表单以引导用户提交或删除文件 —— 同样是转换到其他的application state。 提倡REST的人同时也希望form这种hypermedia能被程序理解 —— 可以这样上传、删除文件哦。
继续假设现在要添加认证功能。 初始的application state里不包含Authorization这个状态。于是服务器无法获得当前是那个用户这一信息。
假设 /files/anonymous/ 下是允许任何人随便弄的。 对这下面的请求服务器都可以完成。
而如果对这之外的请求, 服务器发现没有Authorization时就可以返回401 Unauthorized并带上WWW-Authenticate。
浏览器就会弹出一个丑陋的框, 要求用户输入账户名与密码。 之后浏览器继续发送上一个application state以及新增加的Authorization到服务器。
这下服务器就有足够的信息判断该用户是否有足够的权限访问。 并根据授权规则显示部分允许被操作的资源的链接。
通过这种方式REST就让application添加了新的Authorization状态。 只是这个状态不容易消除。。。
同样, 提倡REST的人希望401和WWW-Authenticate能被程序理解。
starwing83 发表于 2014-03-24 02:28
那么按照你说的,我是不是可以这么理解S,所谓状态就是:资源的表示能提供访问更多操作的可能性?
也就是说,我不知道有多少用户,我GET /user,得到一个列表,这样我就能对我获取的用户进行操作了——因此状态(就有机会)改变了?不然我就只知道这一个接口,谈不上能改变状态。
这么说,S其实说的不是状态,而是【获取可以进行其他操作的必要信息】,是这个理解么
按我目前的理解, http request里所包含的让服务器足够区别是谁打算做什么操作的信息应该算application state。
上面的例子中还有很多request里的信息是server暂时不感兴趣的。 它们算不算application state就不知道了。
对资源请求产生的representation里可以包含改变application state的方式。 比如link, form, 401等等。
GET /user 里, GET和 /user 应该都是application state。 返回一个列表, 里面的链接就可以引导消费者 GET /user/sw 或 GET /user/ow , 于是application state就从 GET /user 转换到了后两者之一。
资源的表示能提供迁移到其他application state的可能性。
GET /user 可以得到一个列表, 因此application state就有机会改变 —— 就可以请求特定的某个用户。
不然只知道 /user 就不知道应该怎么获取特定的user。 就像最开始那个不支持ls的http文件服务器一样。
"获取可以进行其他操作的信息"就是HATEOAS的内容,这些信息可以引导application 进入其他的S,并将S传递给服务器。
关于token。
假设一开始的application state里是没有的。 当访问了一个需要权限的资源时就会引导用户认证, 然后让application添加这个state。
比如认证成功后在header里加一个 Set-Cookie: token=sw; 暂时抛开安全性问题。。。
于是后续的请求就会发送 Cookie: token=sw。 服务器就知道这是谁在发送请求, 并能根据这点进行授权。
服务器里没有和token相关的记录, 每次请求都必须把这个Cookie重新发送。
而另一种做法。 认证成功后在header里添加一个 Set-Cookies: {J,PHP,...}SESSION_ID=random_key。
同样后续的请求会有 Cookie: PHPSESSION_ID=random_key。 服务器也可以通过random_key查询一个lookup table获得该SESSION里的数据,比如user。
于是RWS(不太记得到底是不是这本书里这么说的,还是其他地方)就分情况了。。。
如果lookup table是服务器内存里的一个数据结构, 那这就是将application state(哪个用户发起的请求)放在了server state里。
这样的区分确实有好处。 假设有多个logic server。
前一种 Cookie: token=sw的方式, load balancer无论将它转发到哪个logic server都是可以工作的。 并且每一个logic server都是crash only。 挂了后重启就是。
而后一种 Cookie: PHPSESSION_ID=random_key 的话, load balancer就需要支持session stick。 比如另外添加一个 Set-Cookie: server=1。 然后根据传回的Cookie: server=1将这个请求继续转发回server1。
或者修改PHPSESSION_ID为S1PHP_SESSION_ID,然后根据它选择server1后又改回PHPSESSION_ID。
同时,如果server1挂了, 之前粘着在server1上的用户的登录状态就一起挂了。
也就是说前一种方式每个请求与每个服务器之间没有亲缘性, 而后一种就会有。
但有时候一些机密的东西不能发回到客户那里。。。 于是RWS松口了。。。
说在这种情况下,不要把那个lookup table放在逻辑服务的内存里。。。 应该放在持久化存储里。。。 比如数据库或redis(开启持久化机制)之类的东西里。。。
总之。。。 No Silver Bullet。。。 |
|