Search code examples
postapache-flexhttpservice

Can I control the parameter order in an HTTPService Post?


I'm updating a Point of Sale system that was built with Flex 4.15.0 and AIR 23.0 using the Cairngorm framework.

The code integrates with a custom server provided by my client's payment processor vendor. I do not know any details of its implementation.

Part of the requirements is that parameters be form posted to their server in a specific order. The Apache Flex / AIR does not appear to retain the parameter order of the object's parameters. Is there a way to do it?

More specifics, with code:

  1. The HTTPService is set up in Cairngorm's Services.mxml:

    <mx:HTTPService id="service"
                showBusyCursor="false"
                requestTimeout="240"
                method="post" contentType="application/x-www-form-urlencoded"
                url="http://localhost.:16448/" resultFormat="e4x"
                /> 
    
  2. Create a parameter object and call service method; this is done in a Cairngorm Delegate:

    var parameters : Object = new Object();
    parameters.firstParameter  = "firstOne";
    parameters.amount = 100;
    parameters.otherParameters = "Other Random Misc Data";
    parameters.lastParameter = "LastOne";
    

Then make the call:

var call : Object    = this.service.send(parameters);
call.addResponder( this.responder ); 
  1. The Flex Framework class mx.rpc.httpAbstractOperation adds the parameters object to the outgoing service call. This starts around line 862. This loops over properties using classinfo.properties. This seems to get an alphabetical list of properties from my object and add them to the paramsToSend object:

    else if (ctype == CONTENT_TYPE_FORM)
    {
        paramsToSend = {};
        var val:Object;
    
        if (typeof(parameters) == "object")
        {
            //get all dynamic and all concrete properties from the parameters object
            var classinfo:Object = ObjectUtil.getClassInfo(parameters);
    
            for each (var p:* in classinfo.properties)
            {
                val = parameters[p];
                if (val != null)
                {
                    if (val is Array)
                        paramsToSend[p] = val;
                    else
                        paramsToSend[p] = val.toString();
                }
            }
        }
        else
        {
            paramsToSend = parameters;
        }
    }
    
  2. Looking at the raw data in the Flash Builder Network Monitor; the final request doesn't have the parameters in alphabetical order.

    otherParameters=Other%20Random%20Misc%20Data&lastParameter=LastOne&firstParameter=firstOne&amount=100
    

    With this small sample it appears that the parameters are in reverse alphabetical order, but with the actual request data they are in a seemingly random--but always consistent--order.

Something appears to be modifying the request between leaving Flex and hitting the network monitor. I assume something in the runtime.

My first attempt at a solution was to create the POST parameter string manually and use that as the parameter object. However in that case the body of the POST request was blank when reviewing it in the service monitor.

Any ideas? I'm at a loss, and fear that the parameter order may be a reason for the vendor to deny PCI Compliance certification of the app's updates.

Here is a related question that offers a solution to GET calls, but not POST calls.


Solution

  • My guess is you'll have to manually generate the POST body yourself, and use the more low-level URLLoader object instead of HTTPService.

    I'd pattern it off of https://madssj.com/blog/2008/07/30/actionscript-3-posting-xml-data-with-urlloader/

    And, if anyone doesn't know what a raw POST body looks like, it's basically a URL query string: How are parameters sent in an HTTP POST request?


    Using the lower level APIs was the right approach to control the parameter order. Here is some sample code that I used. First, create the parameter string:

    var parameters : String = '';
    parameters += "firstParameter=firstOne&";
    parameters += "amount=100&";
    parameters += "otherParameters=Other Random Misc Data&";
    parameters+= "lastParameter=LastOne";
    

    Then, create the URLRequest:

    var r:URLRequest = new URLRequest(yourURLHere);
    r.data = parameters;
    r.method = URLRequestMethod.POST;
    r.contentType = "application/x-www-form-urlencoded";
    

    And finally, create the URLLoader:

    var l:URLLoader = new URLLoader();
    l.addEventListener(Event.COMPLETE, myResultMethod);
    l.addEventListener(IOErrorEvent.IO_ERROR, myFailureMethod );
    l.addEventListener(SecurityErrorEvent.SECURITY_ERROR, myFailureMethod );
    l.load(r);
    

    And you now have complete control over the parameter order.

    My blog post on this topic.