我正在开发一个 flex 应用程序(在 Web 浏览器中运行),它允许用户加载许多文件,然后在一个单一的 multipart/form-data 请求中将它们全部发送到服务器。
我的问题是:
出于安全原因,flash 要求用户通过单击按钮来启动 URLLoader.load 操作。没关系,用户单击应用程序中的保存按钮,然后我们就走了。
不幸的是,请求的上传部分似乎不是异步的,而只是下载部分。数据可以是任意大小,因为用户可以添加任意数量的文件,因此上传可能需要一段时间才能完成。
在一个理想的世界里,我会在保存按钮的点击处理程序中做这样的事情:
PopupManager.createPopup(this, ProgressDialog, true);
doUpload();
不幸的是,这将导致在上传完成后显示进度对话框。那么,我可以像这样将上传开始推迟到弹出窗口显示之前吗?
PopupManager.createPopup(this, ProgressDialog, true);
setTimeout(doUpload, 100);
结果我也不能这样做,因为上面提到的安全原因。这将引发 SecurityError:错误 #2176。
基本上问题是
- 在当前帧中的代码完成之前,弹出窗口将不可见
- URLLoader.load 阻塞,直到请求的上传部分完成
- 弹出窗口来得太晚了,因为耗时的部分已经结束。
- 我等不及弹出窗口了,因为加载操作必须由用户单击启动。
有什么办法可以解决这个限制吗?
这是一个说明问题的小应用程序。按钮二和三将抛出 SecurityError。
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="419" height="250">
<fx:Script>
<![CDATA[
import mx.core.IFlexDisplayObject;
import mx.managers.PopUpManager;
private var urlLoader:URLLoader;
private var popup:IFlexDisplayObject;
protected function sendNowButton_clickHandler(event:MouseEvent):void {
trace(">> URLLoaderSendTest.sendNowButton_clickHandler(event)");
popup = PopUpManager.createPopUp(this, ProgressDialog, true);
doLoad();
trace("<< URLLoaderSendTest.sendNowButton_clickHandler(event)");
}
protected function sendWithSetTimeoutButton_clickHandler(event:MouseEvent):void {
trace(">> URLLoaderSendTest.sendLaterButton_clickHandler(event)");
popup = PopUpManager.createPopUp(this, ProgressDialog, true);
setTimeout(doLoad, 200);
trace("<< URLLoaderSendTest.sendLaterButton_clickHandler(event)");
}
protected function sendWithCallLaterButton_clickHandler(event:MouseEvent):void {
trace(">> URLLoaderSendTest.sendWithCallLaterButton_clickHandler(event)");
popup = PopUpManager.createPopUp(this, ProgressDialog, true);
callLater(doLoad);
trace("<< URLLoaderSendTest.sendWithCallLaterButton_clickHandler(event)");
}
private function doLoad():void {
trace(">> URLLoaderSendTest.doLoad()");
var bytes:ByteArray = new ByteArray();
bytes.writeInt(1);
var request:URLRequest = new URLRequest("http://localhost/test/");
request.method = URLRequestMethod.POST;
request.contentType = "multipart/form-data";
request.data = bytes;
urlLoader = new URLLoader();
urlLoader.addEventListener(Event.COMPLETE, loaderComplete);
urlLoader.load(request);
trace("<< URLLoaderSendTest.doLoad()");
}
protected function loaderComplete(event:Event):void {
trace(">> URLLoaderSendTest.loaderComplete(event)");
PopUpManager.removePopUp(popup);
}
]]>
</fx:Script>
<s:Button id="sendNowButton" x="10" y="10"
label="Send now"
click="sendNowButton_clickHandler(event)"/>
<s:Button id="sendWithsetTimeoutButton" x="10" y="40"
label="Send with setTimeout"
click="sendWithSetTimeoutButton_clickHandler(event)"/>
<s:Button id="sendWithCallLaterButton" x="10" y="70"
label="Send with callLater"
click="sendWithCallLaterButton_clickHandler(event)"/>
</s:Application>