8 Replies Latest reply on Apr 5, 2013 3:11 AM by John Michael Vincent Rustia

    AsyncHttp in Javascript API

      I am not getting the full response body in the javascript callback when using AsyncHttp from javascript API.

      The callback method is being called but do not have the @params["body"].

       

      I am getting only this data from the javascript callback of an Rho.AsyncHttp.post API.

      rho_callback:1

      status:ok

      http_error:200

       

      From the rholog.txt, here's the log

       

      APP| Params: {"data"=>"{\"module\":\"Rho::AsyncHttp\",\"method\":\"post\",\"args\":[\"http://localhost/SmartHandsATTCellSite/mobile/rhoconnect/homeNotif\",{\"Content-Type\":\"application/json\",\"Accept\":\"application/json\"},\"{\\\"username\\\": \\\"gnis\\\", \\\"request\\\": \\\"home notif\\\"}\",\"/app/RhoJavascriptApi/callback_handler__rhoID0\",\"callback=test\"],\"callback_index\":3}"}

      I 02/18/2013 17:31:18:608 000010dc                JSAPI| respond_to?, name: command_handler

      I 02/18/2013 17:31:18:609 000010dc                JSAPI| command_handler: {"data"=>"{\"module\":\"Rho::AsyncHttp\",\"method\":\"post\",\"args\":[\"http://localhost/SmartHandsATTCellSite/mobile/rhoconnect/homeNotif\",{\"Content-Type\":\"application/json\",\"Accept\":\"application/json\"},\"{\\\"username\\\": \\\"gnis\\\", \\\"request\\\": \\\"home notif\\\"}\",\"/app/RhoJavascriptApi/callback_handler__rhoID0\",\"callback=test\"],\"callback_index\":3}"}

      I 02/18/2013 17:31:18:611 000010dc                JSAPI| command_handler, callback_id: __rhoID0

      I 02/18/2013 17:31:18:612 000010dc                  APP| method_args : ["http://localhost/SmartHandsATTCellSite/mobile/rhoconnect/homeNotif", {"Content-Type"=>"application/json", "Accept"=>"application/json"}, "{\"username\": \"gnis\", \"request\": \"home notif\"}", "/app/RhoJavascriptApi/callback_handler__rhoID0", "callback=test"]

      I 02/18/2013 17:31:18:613 000010dc                JSAPI| AsyncHttp.post PROXY

      I 02/18/2013 17:31:18:614 000010dc                JSAPI| DEFAULT PROXY, Rho::AsyncHttp.post, args: [{:url=>"http://localhost/SmartHandsATTCellSite/mobile/rhoconnect/homeNotif", :headers=>{"Content-Type"=>"application/json", "Accept"=>"application/json"}, :body=>"{\"username\": \"gnis\", \"request\": \"home notif\"}", :callback=>"/app/RhoJavascriptApi/callback_handler__rhoID0", :callback_param=>"callback=test"}]

      I 02/18/2013 17:31:18:616 000010dc            AsyncHttp| addCommand: POST

      I 02/18/2013 17:31:18:623 000010dc                  APP| res : {"value":null,"type":"null"}

      I 02/18/2013 17:31:18:631 000010dc           HttpServer| GC Start.

      I 02/18/2013 17:31:18:638 000010dc           HttpServer| GC End.

      I 02/18/2013 17:31:18:639 000010dc           HttpServer| Process URI: '/public/images/workorder.png'

      I 02/18/2013 17:31:18:642 000010dc           HttpServer| Process URI: '/public/images/email.png'

      I 02/18/2013 17:31:18:644 000010dc           HttpServer| Process URI: '/public/images/star.png'

      I 02/18/2013 17:31:18:647 000010dc           HttpServer| Process URI: '/public/jqmobile/images/icons-18-white.png'

      I 02/18/2013 17:31:18:648 000012f4                  Net| Method: POST;Url: http://localhost/SmartHandsATTCellSite/mobile/rhoconnect/homeNotif

      I 02/18/2013 17:31:18:670 000010dc           HttpServer| Process URI: '/public/images/ajax-loader.gif'

      E 02/18/2013 17:31:18:671 000010dc           HttpServer| The file /public/images/ajax-loader.gif was not found

      I 02/18/2013 17:31:18:673 000010dc           HttpServer| Process URI: '/public/jqmobile/images/ajax-loader.gif'

      I 02/18/2013 17:31:18:703 00000ed0         QtMainWindow| Page load complete.

      I 02/18/2013 17:31:18:720 000012f4                  Net| Method: POST;Url: http://127.0.0.1:62697/app/RhoJavascriptApi/callback_handler__rhoID0

      I 02/18/2013 17:31:18:725 000010dc           HttpServer| Process URI: '/app/RhoJavascriptApi/callback_handler__rhoID0'

      I 02/18/2013 17:31:18:726 000010dc                  APP| RHO serve: /app/RhoJavascriptApi/callback_handler__rhoID0

      I 02/18/2013 17:31:18:761 000010dc                  APP| Params: {"rho_callback"=>"1", "status"=>"ok", "http_error"=>"200", "headers"=>{"content-type"=>"application/json", "date"=>"Mon, 18 Feb 2013 09:31:18 GMT", "server"=>"Apache-Coyote/1.1", "transfer-encoding"=>"chunked"}, "__rho_object"=>{"body"=>"0"}, "callback"=>"test"}

      I 02/18/2013 17:31:18:763 000010dc                JSAPI| respond_to?, name: callback_handler__rhoID0

      I 02/18/2013 17:31:18:763 000010dc                JSAPI| method_missing, name: callback_handler__rhoID0

      I 02/18/2013 17:31:18:764 000010dc                JSAPI| method_missing, match to callback: 0

      I 02/18/2013 17:31:18:764 000010dc                JSAPI| method_missing, match to command:

      I 02/18/2013 17:31:18:789 000010dc                JSAPI| callback PROXY, id: __rhoID0, js_params: {"rho_callback":"1","status":"ok","http_error":"200","headers":{"content-type":"application\/json","date":"Mon, 18 Feb 2013 09:31:18 GMT","server":"Apache-Coyote\/1.1","transfer-encoding":"chunked"},"callback":"test","body":{"message":"homeNotif request"}}, @request: {"application"=>"app", "model"=>"RhoJavascriptApi", "action"=>"callback_handler__rhoID0", "request-method"=>"POST", "request-uri"=>"/app/RhoJavascriptApi/callback_handler__rhoID0", "request-query"=>"", "headers"=>{"Content-Type"=>"application/x-www-form-urlencoded", "User-Agent"=>"rhodes-wm", "Host"=>"127.0.0.1:62697", "Content-Length"=>"246", "Connection"=>"Keep-Alive", "Cache-Control"=>"no-cache"}, "request-body"=>"rho_callback=1&status=ok&http_error=200&headers[content-type]=application%2fjson&headers[date]=Mon%2c%2018%20Feb%202013%2009%3a31%3a18%20GMT&headers[server]=Apache-Coyote%2f1.1&headers[transfer-encoding]=chunked&__rho_object[body]=0&callback=test", :modelpath=>"C:/Users/jrustia/rhoworkspace/SmartHandsClient/app/RhoJavascriptApi/"}

      E 02/18/2013 17:31:18:789 000010dc                JSAPI| callback PROXY js call: Rho.callback_handler('__rhoID0', {"rho_callback":"1","status":"ok","http_error":"200","headers":{"content-type":"application\/json","date":"Mon, 18 Feb 2013 09:31:18 GMT","server":"Apache-Coyote\/1.1","transfer-encoding":"chunked"},"callback":"test","body":{"message":"homeNotif request"}});

      I 02/18/2013 17:31:18:789 00000ed0           MainWindow| navigate: 'javascript:Rho.callback_handler('__rhoID0', {"rho_callback":"1","status":"ok","http_error":"200","headers":{"content-type":"application\/json","date":"Mon, 18 Feb 2013 09:31:18 GMT","server":"Apache-Coyote\/1.1","transfer-encoding":"chunked"},"callback":"test","body":{"message":"homeNotif request"}});'

        • Re: AsyncHttp in Javascript API

          In addition to the code above, heres the javascript code

           

          function getHomeNotificationCount() {
                  Rho.AsyncHttp.post(
                    "http://localhost/SmartHandsATTCellSite/mobile/rhoconnect/homeNotif",
                     {"Content-Type" : "application/json", "Accept" : "application/json"} ,
                     '{"username": "gnis", "request": "home notif"}',
                     _callback,
                     "callback=test"
                  );
                }
                function _callback(data) {
                  $.each(data,function(key,value){
                    console.log(key + ":" + value);
                  });
          
                  populateHomeNotification({})
                }   
          

           

          I have no issues with javascript code. Only issue is, it seems that while response data is transfering in chunked from the server, the callback method is already called before the response body is even completed.

            • Re: AsyncHttp in Javascript API
              Robert Galvin

              Anyway to see if you changed the server response to not be chunked will it work ok? The JS for RhoAsync HTTP is fairly new (we have had the Ruby flavor of it for some time), so it may have a bug under this condition. Have you tried other Async APIs like from Jquery

              1 of 1 people found this helpful
                • Re: AsyncHttp in Javascript API

                  I haven't tried to changed the server response, cause its doing the default process anyway, I mean all our applications is also connecting to the same server with the same configurations. I already tried WebView.navigate to access the same web application from our server and all ajax requests are working fine. What I understand, is when I used the $.ajax API of jquery or XMLHttpp request in a .erb file(our normal jsp are ported to .erb files as views), the request is not being sent to the external service, rather is to the rhodes ruby controller. I think rhoelements changed the definition of ajax of a jquery mobile/jquery API on the fly when building. The AsyncHttp could work on the controller side with no issues I believe, but on the JS there is real issue. I understand that the AsyncHTTP in JS is actually throwing the request first behind the scene on a local controller of Rhodes and the concerned rho_javascript_controller will actually relay the request as well to the external service defined by the url pass from the javascript. Before the controller receives the complete request, it is already responded to the javascript callback function with status ok but with empty request body. This could be a bug, and could be fix if the rho_javascript_controller would have to wait first for the whole response to be completed before calling the javascript callback function. That is my theory though, I could be wrong.

                   

                  We want to port all our jsp pages to erb files with minimal change. The main issue that my team is concerned about is to make the ajax works the same way as before by using the AsyncHttp API as the focal point of all ajax request, thus we would just need to change a single JS file with no changes on other html/js files dependent to it.

                   

                  Any help would be gladly appreciated, any alternatives do you have?

              • Re: AsyncHttp in Javascript API

                I think I wouldn't be able to continue with javascript AsyncHTTP API, since the said issue could be an internal bug. Anyway I still have found a suited solution to our needs and I think it could benefit anyone who come across the same problem.

                 

                The design that we applied on making the normal javascript ajax works on rhomobile MVC architecture, is to let the javascript as it is, and use the AsyncHTTP API in a common controller where we call it AjaxController. It would be a single entry point for all javascript ajax call, and this controller would relay the ajax request to the external backend server using AsyncHttp. In the callback on ruby controller, it has to find out how to throw back the response to javascript page and this is via WebView.execute_js. The issue that comes to play is the common way of registering javascript ajax callback function is via anonymous function, and WebView.execute_js has no way to trigger that. Another thing is the ajax request on javascript is already closed while the controller is relaying the request to external server. In our current framework all of our ajax call use anonymous function for callback function. So we dont want to change all of that and declare them with global names. So to maintain minimal changes, we also provide a single entry point of calling a callback function on the javascript, by using a single global namespaced function that receives the response from the controller, and would have the responsibility in dispatching the response back to the matching ajax caller.In this way, all ajax call would throw the request to single controller, and all backend server respose would be thrown back by the ajax controller to a single javascript namespaced function.

                 

                This namespaced function is a part of a jquery plugin and always present in every page so all ajax request is abstracted on this plugin. The anonymous ajax callback function is not anymore included in the jquery ajax call, but instead would be cached in the jquery plugin namespaced. All in all, the changes are added a namespaced function that receives the response from the controller, added a namespaced function that contains the registered ajax callback function: a singleton ajax design(you can use queu/list to support concurrent ajax call, then an id is needed to indentify matching ajax and callback function), and lastly the passed url on the plugin will translate it as part of the form data to be used by the ruby controller AsyncHttp, and and the jquery ajax would always relay the request to the url of the ruby controller. All this changes are packed in our own custom jquery plugin that normalizes all ajax call. So very minimal changes, and no changes at all on the pages with inline scripts or in other javascripts files that depends on this plugin for ajax call.

                 

                This design I believe could be the easiest way to leverage our existing front end framework with rhomobile environment, and I think the common way other developers had figured out already.

                  • Re: AsyncHttp in Javascript API
                    Nicolas Grolleau

                    Hi, I encountered the same problem as you.

                    I noticed in the documentation that

                    In the case of a JSON response (Content-Type=“application/json”), the @params["body"] will be parsed automatically and contain a ruby data structure. Otherwise, @params["body"] contains the raw response body.

                     

                    So I tried to modify my server to remove the  "application/json" header from the response and voilà, the body was back in the answer.

                     

                    As my server is called by other apps, I can't remove the header, but at least it's an explanation...

                     

                    Maybe there is a way to disable the automatic parsing or retreive the ruby data structure?

                      • Re: AsyncHttp in Javascript API

                        Your issue is a different actually with mine. The actual root cause of this post is because of the AsyncHttp API in javascript level is buggy and not working in my code and according to robert it could be a bug since this api in javascript is a quite new. So AsyncHttp API in the ruby is a better approach and more stable.

                         

                        Your issue about headers though is important whether you send request from javascript or from ruby controller. And I have already done the same code in ruby controller and javascript without changing the backend server implementation, and its working in the ruby level, so its not a server issue but the rhomobile API issue. But at least you have shed another supporting fact. Anyway, thanks for sharing your experience.

                          • Re: AsyncHttp in Javascript API
                            Nicolas Grolleau

                            I think you misunderstood what I meant.

                             

                            Your issue as I understand it is that you were trying to use javascript  AsyncHttp API to communicate with a server answering with a JSON response and got no body in the server response, right?

                            So it is exactly the same as the issue I encounter.

                             

                            What I tried to demonstrate by modifying header in the server response was that I do not encounter the bug if the server response is plain text and not JSON.

                            So my conclusion is that the bug in the javascript API may be caused by the automatic parsing of the JSON response described in the documentation for the ruby API that may also happen with the javascript and shouldn't.

                             

                            Anyway, I agree with you that due to this bug it would be better to use AsyncHttp in the ruby api, but unfortunatly I don't know much about ruby and my app is at the moment 100% javascript.

                            Do you know if I could find somewhere some sample of how to interact between a javasctipt app and a ruby controller?

                              • Re: AsyncHttp in Javascript API

                                Another work around though is to use Ruby Controller which I have taken especially I needed it for offline database facility which only available in ruby, the Rhom API. In this way if AsyncHttp API fails in Ruby due to internet connection issue, it will call a module that uses Rhom to store the data temporarily and Rhoconnect will sync the data once the device gets online. A javascript code calling a ruby controller is just like a normal ajax call such as :

                                 

                                function getPicCallback(opt){

                                      $.ajax({

                                        url : "/app/RubyController/async_post",

                                        data : {

                                          filename : opt.image_uri

                                        },

                                        type: "post",

                                        success : function(data) {

                                          //sample

                                        }

                                      });

                                    }

                                 

                                the ruby controller will look like this

                                 

                                class RubyController < Rho::RhoController

                                  include  BrowserHelper, ApplicationHelper

                                def async_post

                                    Rho::AsyncHttp.post(

                                    :url => @params['url'],

                                    :headers => headers,

                                    :body =>  body,

                                    :callback => url_for(:action => :httppost_callback),

                                    :callback_param => callback_param

                                    )

                                  end

                                def httppost_callback

                                errorCode = ( (blank?@params['http_error']) ? @params['error_code'] : @params['http_error'] )

                                    WebView.execute_js("console.log('javascript callback')")

                                    if(blank?errorCode or errorCode != "200")

                                      errorMsg = ((blank?@params['http_error']) ? Rho::RhoError.new(@params['error_code']).message : @params['body'])

                                      map = ::JSON.generate({"error" =>  errorMsg})

                                      WebView.execute_js("$.SH.ajaxResponseFunction(#{map},#{errorCode},\"#{@params["ajax_callback_id"]}\")")

                                    else

                                      #no http error

                                      jsonResponse = ::JSON.generate(@params['body'])

                                      WebView.execute_js("$.SH.ajaxResponseFunction(#{jsonResponse},#{errorCode},\"#{@params["ajax_callback_id"]}\")")

                                    end

                                  end

                                end

                                Links for MVC structure of Rhomobile and some tutorials

                                http://docs.rhomobile.com/rhodes/application

                                http://docs.rhomobile.com/rhoelements/rhoelements-tutorial