其实任何能够完整地支持HTTP 1.1协议的客户端技术都能够很好地支持REST。浏览器中的XMLHttpRequest对象没有问题(IE和
Firefox可以支持所有的HTTP方法,Safari不支持PUT和DELETE方法),因此可以使用Ajax开发很好的REST客户
端。Java、C#、Ruby、Perl、Delphi等等编程语言都不会有问题。
说到Flex,它本身不太适合开发REST客户端。我关注这个问题有一年了,现在看来情况还是如此。
这件事的缘起是我想找到一个能够与服务器端的Rails相配合的ActionScript 3语言开发的REST客户端库,也就是一个
ActiveResource的AS3版。
我们来看看网上的一些讨论。
Flex can't do REST
http://www.fngtps.com/2007/06/flex-can-t-do-rest
在这个讨论中,Thijs van der Vossen说:
There’s no way to extract the headers from an HTTP response in
ActionScript 3 so you can’t get the id of a newly created resource
from the ‘Location’ header and you can’t tell the difference between a
‘500 Internal Server Error’, a ‘404 Not Found’ or a ‘422 Validation
Error’.
没有办法从ActionScript 3的HTTP响应中获取到头信息字段,这样你就无法从Location头信息字段中获取到新创建资源的id。你也
无法区分500和404、422等等响应状态码(因为你无法得到这些状态码)。
There’s also no way to get the response body for anything not in the
2xx range.
当响应状态码不在2xx区间内的时候,你没有办法得到响应的消息体。
Oh, and you can only do a GET or a POST, no PUT or DELETE, at least
not without a proxy.
这到并不是非常大的问题,Safari中的XMLHttpRequest对象同样也不支持,不过我们可以使用POST + method参数来模拟
PUT和DELETE方法,虽然这种做法不大优雅。
Can AS3 do REST, or not?
http://www.atnan.com/2007/6/11/can-as3-do-rest-or-not
在另一个讨论中,Nathan de Vries对于Thijs van der Vossen的说法提供了有力的支持:
I’d put money on the fact that Adobe is unwilling to provide access to
the headers because the functionality is not available in all
browsers. Their opinion – as a guess – is that the Flash plugin should
operate in an identical fashion across all browsers.
Thijs回复Nathan说:
Then lower it states that ‘a value of 0 can be generated in any player
(for example, if a malformed URL is requested), and a value of 0 is
always generated by the Flash Player plug-in when it is run in the
following browsers, which do not pass HTTP status codes to the player:
Netscape, Mozilla, Safari, Opera, and Internet Explorer for the
Macintosh.’
So, it seems that you can only get the status when you’re running
inside Internet Explorer on Windows.
Just wondering, have you been able to get the
flash.events.HTTPStatusEven.responseHeaders when you’re running in an
environment where the status code is not passed to the player?
Nathan回复Thijs说:
@Thijs: There really isn’t any workaround other than building a
URLLoader equivalent with XMLSocket, and proxying all requests through
a domain with a valid cross-domain policy file.
As for ‘0’ status codes…you’re correct. I’ve written up a quick
example
也就是说,因为Flash Player无法从浏览器得到HTTP响应状态码,因此程序自然也就无法从Flash Player中获取到状态码。问题并
不是出在HTTPService类上面,而是出在更底层的URLLoader类上面。解决办法是使用XMLSocket来重新开发一个
URLLoader类的对等实现。
另外在两个讨论中还提到,Adobe AIR中并不存在这些问题(无法得到响应的HTTP头信息字段和状态码),因此AIR可以用来实现一个很好的
REST客户端。但是AIR是用来开发桌面应用的,我们真正想开发的还是运行于浏览器中的Web应用。
在第一个讨论中Alex MacCaw回复说:
So, a socket urlloader is the way forward - if you look in the source
of my project, ActiveResource for Actionscript you'll find an example
of such a class.
原来Alex MacCaw同学早已解决了这个问题,他还发布了一个开源软件,正是我要找的ActiveResource的AS3版:
http://www.eribium.org/blog/?p=74
http://www.eribium.org/blog/?p=88
这个开源软件发布在:
http://code.google.com/p/as3-active-resource/
我们来看看例子代码:
var delegate:Asset = new Asset( this );
var o:Object = new Object()
o.id = 1
o.name = “foo.png”
delegate.save(o)
这段代码有两个主要的问题:
1. 我们必须事先创建Asset类。假设服务器端有一个Asset类,除了在服务器端定义这个类外,我们还需要在客户端的AS3中定义这个类,这就带
来了重复代码的问题。假如我有50个Model类暴露给客户端,我就要重复定义50次。而我希望能够像Ruby那样动态创建这个类。使用AS3,你就别
指望了,因为AS3不支持动态创建一个类。
2. 必须要通过委托的方式来操作Model对象,而不能写成:
o.save()
例子中写法是JavaEE中的DAO的写法,我们知道如果支持实现充血模型,其实根本就不需要什么DAO。o.save()的写法显然更加OO。
The project is made with Cairngorm in mind, and utilises the
IResponder interface.
从个人品味上来说,我很不喜欢复杂的Cairngorm,为什么不是设计的更加优雅、更加简练易用的PureMVC?不就是一个
ActiveResource接口的实现吗?真的还需要引入一个复杂的MVC框架吗?
以上的原因使得我最终放弃了使用as3-active-resource的念头,而且这个库看起来也不是很成熟。
后来我决定通过Flex-Ajax Bridge调用Jester的功能来开发REST客户端,这样做可以解决上述的两个问题。这一决定又引来了一番天
昏地暗的hack,且听我下回分解。:)