I would like to know when does Flex's HTTPService launches a ResultEvent and when does it dispatches a FaultEvent.
When the servers response contain a 401 http status code error (Unauthorized), the HTTPService is dispatches a ResultEvent instead of a FaultEvent. I would assume that it should dispatch a FaultEvent. Am I correct? If not please tell me.
The amazing thing is that when I'm running the application under the Flash Builder 4.7's Android Simulator, it does dispatch a FaultEvent, but when I run it on the device, it dispatches the ResultEvent. Why is this happening? Any ideas?
Test application code
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="HomeView">
<fx:Script>
<![CDATA[
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
///////////////////////////// USING HIGH LEVEL COMPONENT (FLEX) //////////////////////////////////////////
/**
* Checks if all the necesary data was entered by the user.
*/
protected function configHandler(event:MouseEvent):void
{
textArea.text = "Connecting to server using a high level component";
configurationService.url = "http://10.0.0.221/api/v1/room/current/";
configurationService.headers.Accept = "application/json";
configurationService.send();
textArea.appendText("\n...");
}
/**
* Handles the first phase (getting basic application information) of the configuration.
* Stores the retrieved data from the server and calls the second phase of the process.
*/
protected function serviceResultHandler(event:ResultEvent):void
{
textArea.appendText("\n");
textArea.appendText("Entering serviceResultHandler \n");
textArea.appendText(" HTTP status code is: " + event.statusCode);
}
/**
* Handles errors within the first phase (getting basic application information) of the configuration process.
*/
protected function servicefaultHandler(event:FaultEvent):void
{
textArea.appendText("\n");
textArea.appendText("Entering servicefaultHandler \n");
textArea.appendText("HTTP status code is: " + event.statusCode);
}
///////////////////////////// USING LOW LEVEL COMPONENT (FLASH) //////////////////////////////////////////
/**
* Checks if all the necesary data was entered by the user.
*/
protected function config2Handler(event:MouseEvent):void
{
textArea.text = "Connecting to server using a low level component \n ...";
var loader:URLLoader = new URLLoader();
var request:URLRequest = new URLRequest("http://10.0.0.221/api/v1/room/current/");
request.requestHeaders = new Array( new URLRequestHeader('Accept','application/json'));
try {
loader.load(request);
} catch (error:Error) {
trace("Unable to load requested document.");
}
loader.addEventListener(Event.COMPLETE, completeHandler);
loader.addEventListener(Event.OPEN, openHandler);
loader.addEventListener(ProgressEvent.PROGRESS, progressHandler);
loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
loader.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
}
private function completeHandler(event:Event):void {
var loader:URLLoader = URLLoader(event.target);
textArea.appendText("\n");
textArea.appendText("Entering completeHandler \n");
textArea.appendText("completeHandler: " + loader.data + "\n");
var vars:URLVariables = new URLVariables(loader.data);
textArea.appendText("The answer is " + vars.answer);
}
private function openHandler(event:Event):void {
textArea.appendText("\n");
textArea.appendText("Entering openHandler \n");
textArea.appendText("openHandler: " + event);
}
private function progressHandler(event:ProgressEvent):void {
textArea.appendText("\n");
textArea.appendText("Entering progressHandler \n");
textArea.appendText("progressHandler loaded:" + event.bytesLoaded + " total: " + event.bytesTotal);
}
private function securityErrorHandler(event:SecurityErrorEvent):void {
textArea.appendText("\n");
textArea.appendText("Entering securityErrorHandler \n");
textArea.appendText("securityErrorHandler: " + event);
}
private function httpStatusHandler(event:HTTPStatusEvent):void {
textArea.appendText("\n");
textArea.appendText("Entering httpStatusHandler \n");
textArea.appendText("httpStatusHandler: " + event);
}
private function ioErrorHandler(event:IOErrorEvent):void {
textArea.appendText("\n");
textArea.appendText("Entering ioErrorHandler \n");
textArea.appendText("ioErrorHandler: " + event);
}
]]>
</fx:Script>
<fx:Declarations>
<s:HTTPService id="configurationService"
result="serviceResultHandler(event)" fault="servicefaultHandler(event)"/>
</fx:Declarations>
<s:Button label="High Level" click="configHandler(event)"
horizontalCenter="100" top="20" />
<s:Button label="Low Level" click="config2Handler(event)"
horizontalCenter="-100" top="20"/>
<s:TextArea id="textArea"
left="20" right="20" top="{configButton.y + configButton.height + 20}" bottom="20"/>
</s:View>
Results on the Flash Builder Simulator
When pressing the "Low Level" button (URL Loader) the text on the text area was:
Connecting to server using a low level component ... Entering openHandler openHandler: [Event type="open" bubbles=false cancelable=false eventPhase=2] Entering httpStatusHandler httpStatusHandler: [HTTPStatusEvent type="httpStatus" bubbles=false cancelable=false eventPhase=2 status=401 responseURL=null] Entering ioErrorHandler ioErrorHandler: [IOErrorEvent type="ioError" bubbles=false cancelable=false eventPhase=2 text="Error #2032: Stream Error. URL: http://10.0.0.221/api/v1/room/current/" errorID=2032]When pressing the "High Level" button (HTTPService) the text on the text area was:
Connecting to server using a high level component ... Entering servicefaultHandler HTTP status code is: 401
Results on the Android device
When pressing the "Low Level" button (URL Loader) the text on the text area was:
Connecting to server using a low level component ... Entering openHandler openHandler: [Event type="open" bubbles=false cancelable=false eventPhase=2] Entering httpStatusHandler httpStatusHandler: [HTTPStatusEvent type="httpStatus" bubbles=false cancelable=false eventPhase=2 status=401 redirected=false responseURL=null] Entering completeHandler completeHandler:When pressing the "High Level" button (HTTPService) the text on the text area was:
Connecting to server using a high level component ... Entering serviceResultHandler HTTP status code is: 401
When I ran the app on the Flash Builder's Simulator, both components worked as expected, meaning that they dispatched a FaultEvent and an IOErrorEvent. On the Android device each component misbehaived, the first dispatching a ResultEvent and the second one an Event.COMPLETE event.
Notice that on both scenarios, both components percieve the correct HTTP status code.
I would assume that there is a problem with the runtime, right? I'd appreciate your comments on the matter.
I think there are some misconceptions here to clear up first:
ResultEventmeans "HTTPServicecall returns successfully." But success in this sense means that we managed to achieve connection and receive the response.It is perfectly valid for the server to respond with any HTTP Status Code, in this case
Status 401 - Unauthorized, indicating you reached the server but tried to access a location you don't have permissions for.FaultEventmeans "HTTPServicecall fails". But here failure is not establishing a connection or not receiving the response.More over
FaultEventis a event wrapper of theFaulterror class which "represents a fault in a remote procedure call (RPC) service invocation". The most common variant isIOError #2032: Stream Error, which is notorious for its ambiguity.Now onto why the different behaviour between your debugger and released build:
When
Capabilities.isDebuggeris true Flash handles errors differently. One documented example is opening a dialog box for on an error occuring.This is speculation as I can't find any documentation, but it would not surprise me to find that
HTTPServicechangesResultEvent : 401intoFaultEvent : 401(thus converting it to aFaulterror) to take advantage of the debug error dialog.