actionscript 3 - AMF 作为 REST 格式,使用 BlazeDS 和 AS3 的 URLLoader



我有一个ColdFusion服务器,它带有一个HTTP API,目前正在返回JSON或XML格式的响应。在内部,所有这些响应都使用ColdFusion"struct"类型表示,然后在呈现给请求客户端之前转换为适当的格式。

使用这个API的客户团队要求除了JSON和XML之外,我们还返回AMF对象。现在,我看到了(并且自己也提出了)反对在REST场景中将AMF用作"返回格式"而不是RPC格式的论点。我对这是否是个好主意的评论不感兴趣——我只想知道它是否有效。如果没有,我希望有明确的理由。如果它能起作用,我希望得到一些关于如何"让它走下去"的指导。

因此,为了实现概念验证示例,我尝试使用BlazeDS序列化一个两元素的ColdFusion数组,然后在Flash Player 10/AS3测试中使用该序列化对象。

以下是服务器端的代码:

//the test object I'm trying to return (keeping it simple)
var testArray = ArrayNew(1); 
testArray[1]="test"; 
testArray[2]="monkey";
//set up output stream to requesting client
var pc       = getPageContext();
var response = pc.getResponse();
var out      = response.getOutputStream();
response.setHeader("Content-Type", "application/x-amf");
//not sure if AmfMessageSerializer is the appropriate class to be using here
var amfMessageSerializer = createObject("java", "flex.messaging.io.amf.AmfMessageSerializer");  
var amfTrace             = createObject("java", "flex.messaging.io.amf.AmfTrace");  //needed by initialize() method
amfMessageSerializer.initialize(variables.SerializationContext.getSerializationContext(), out, amfTrace);
amfMessageSerializer.writeObject(testArray);
out.close(); 

现在,这将生成一些类型的二进制数据。如果我把它放在.cfm中并尝试加载页面,我会得到一些可以在十六进制编辑器中读取的内容,看起来它包含我设置的数组成员。这里有一点需要注意:部分响应消息包括"flex.messageing.io.ArrayCollection"。我还没有足够的知识来知道这个消息告诉了我什么:任何能够提供有关在两个环境之间打字的详细信息的人都会非常感谢我。

下一步是尝试在FlashPlayer端消耗这个。以下是精简版AS3的外观:

myURLloader.dataFormat = URLLoaderDataFormat.BINARY;
myURLloader.addEventListener(Event.COMPLETE, completeHandler);
myURLloader.load(myURLRequest); 
function completeHandler( event : Event) : void
{   
var serverResponse : ByteArray = new ByteArray(); 
serverResponse = event.target.data; 
//read the response into a generic object
var responseObject : Object = new Object(); 
responseObject = serverResponse.readObject();   //fails here: error #2006
}

如注释所示,此操作失败,错误为#2006"提供的索引越界"。我已经搜索了导致此错误的常见原因,但没有找到任何明确的答案。在尝试readObject()之前,我已经尝试将byteArray.position重置为byteArray的开头和结尾——将其更改为结尾会弹出错误#2030"遇到文件结尾"(正如人们所期望的那样),但我已经验证了.position默认为0,这会生成#2006错误。

我敢肯定,这里的问题在于我使用的BlazeDS调用的选择;当我想序列化一个对象时,我想我可能正在序列化一条消息。不幸的是,BlazeDS的JavaDoc自动生成的文档是。。。缺乏启发性。我发现的所有可读性更强的资源都集中在Flash Remoting和RPC示例上。令人惊讶,我知道;但事实就是这样。我使用的是Adobe BlazeDS文档;如果其他人有更好的资源,我会非常感激。

提醒所有回答的人:我意识到这不是AMF的典型用法。我对建议典型RPC方法或切换到Flash Remoting而不是HTTP/GET的响应不感兴趣。我需要的是来自HTTP请求的AMF序列化响应,该响应可以在Flash Player客户端上反序列化实需要知道这是否可能,如果可能,我希望能得到一些关于如何使其发挥作用的指导。我欢迎任何和所有的建议,除了"只是不要使用AMF!"或"只是切换到Flash远程处理!">

更新:在这方面取得了一些进展:
1)在服务器端,我使用blazeDS的ASObject类创建了一个简单的ASObject,并用键值对填充它
2)在客户端和服务器端,我必须确保将对象编码设置为AMF0。AMF3中的相同技术会产生#2006/越界错误,我还不确定为什么。

以下是服务器端的代码:

//set up output stream to requesting client
var pc       = getPageContext();
var response = pc.getResponse();
var out      = response.getOutputStream();
response.setHeader("Content-Type", "application/x-amf");
//not sure if AmfMessageSerializer is the appropriate class to be using here
var amfMessageSerializer = createObject("java", "flex.messaging.io.amf.AmfMessageSerializer");  
amfMessageSerializer.setVersion(variables.MessageIOConstants.AMF0);
var amfTrace  = createObject("java", "flex.messaging.io.amf.AmfTrace");  //needed by initialize() method
amfMessageSerializer.initialize(variables.SerializationContext.getSerializationContext(), out, amfTrace); 
var ASObject = createObject("java", "flex.messaging.io.amf.ASObject"); 
ASObject.put("testKey", "testValue"); //simple key-value map to return to caller
amfMessageSerializer.writeObject(testArray);
out.close(); 

这里的主要区别在于,我不是试图序列化CF数组,而是手动构建一个响应对象(类型为ASObject)。

在客户端,代码现在如下所示:

myURLloader.dataFormat = URLLoaderDataFormat.BINARY;
myURLloader.addEventListener(Event.COMPLETE, completeHandler);
myURLloader.load(myURLRequest); 
function completeHandler( event : Event) : void
{   
var serverResponse : ByteArray = new ByteArray(); 
serverResponse = event.target.data; 
serverResponse.objectEncoding = ObjectEncoding.AMF0; //important
//read the response into a generic object
var responseObject : Object = new Object(); 
responseObject = serverResponse.readObject(); 
trace(responseObject.testKey);                       //displays "testValue", as expected
}

这里的区别在于,我已明确地将ObjectEncoding设置为AMF0(默认为AMF3)。

如果我在服务器和客户端上都将objectEncoding切换到AMF3,我希望一切正常,但我仍然会收到2006:越界错误。ByteArray.length属性在AMF0和AMF3情况下都是相同的,但返回对象的内容不同(在十六进制编辑器中查看时)。

在我提供的第一个示例中更改objectEncoding对产生的错误没有影响。

因此,问题似乎是试图序列化ColdFusion数组:AMFSerializer不知道如何处理它。它需要显式地构建为ASObject。我将构建一个消毒函数来进行这两种类型之间的转换。

我觉得已经取得了进展(感谢所有的评论和回答),但我仍然有很多问题没有得到回答。当我尝试在AMF3中编码时,有人知道为什么会失败,但对于AMF0,而不是吗?我对其中一个没有任何依恋,但我不喜欢这种"把东西扔到墙上,看看哪一个粘在一起"的解决问题的方法。。。我想知道为什么它失败=/

我不久前就这么做了。。你可以在这里查看我的博客文章,也许它能对你有所帮助。我在服务器端使用Java,而不是CF。

最新更新