2

I have a web page that communicates with a node.js backend. I use AJAX to long-poll the server, allowing realtime updates to be received as they occur server-side.

Below is a simplification of my existing client-side code. What I'd like to know is whether there's an equivalent way of doing this with Visualforce/Apex, or can I even host my existing code somehow within an apex page? Any hints, examples or walkthroughs would be more than welcome - I have only been using the Force platform for 3 days so I am still extremely unfamiliar with the technology, terminology, etc.

Also, the data I'm polling for is not Salesforce related, so I don't think the Streaming API will work because the whole topic/query concept is not applicable in this situation.

function poll() {

    longPollRequest = $.ajax({
        url: "http://myserver.com/longPoll",
        type: "GET",
        dataType: "jsonp",
        jsonpCallback: "localJsonpCallback",
        complete: function(jqXHR, textStatus ) {  
            poll(); // restart the poll
        },
        error: function (jqXHR, textStatus, errorThrown) {  }
    });
}

function localJsonpCallback(json) {
    // parse long-poll response
}
3
  • So you just want your VF page to subscribe to a 3rd party service? If so, have you tried any JavaScript libraries for that? – Mike Chale Nov 13 '13 at 15:35
  • This isn't technically salesforce.com related at all, but in the spirit of helpfulness, I've included an answer here that may lead you down the right path. – sfdcfox Nov 13 '13 at 16:00
  • @MikeChale Yep, that's essentially what I want to do. I haven't tried any JS libraries yet - I'm still working out what I can and can't do within a VF page. – Gary Chapman Nov 14 '13 at 2:48
3

Take a look at the Streaming API. You can have your VF page subscribe to a topic and get near real time updates. This blog post does a really good job walking you through setting it up on your page.

1
  • Daniel, thanks for your suggestion. I probably should have been clearer in my question; the data that I'm expecting back from the server has absolutely nothing to do with Salesforce, so the whole idea of queries & topics doesn't really work in my situation. I tried embedding the above code inside a <script> block, but it never executed fully, possibly due to the asynchronous nature of $.ajax(). I also tried sforce.connection.remoteFunction() but it hung. – Gary Chapman Nov 13 '13 at 15:10
2

You can't directly long-poll in Visualforce, except for the aforementioned Streaming API. There is a JavaScript proxy feature that salesforce.com provides, but it only works for single, short-lived requests. What you need is HTML5's Access-Control-Allow-Origin header, with a value set to *. This needs to be implemented on the server-side-- the third-party server-- for this to work.

Basically, it's an extra HTTP header that is sent in a "pre-flight" request that validates if the connection should be allowed. By default, browsers will assume that a missing Access-Control-Allow-Origin header value is the same as the Host header value. This effectively restricts XMLHttpRequest to only connecting to the host that originally served the page, to prevent cross-server scripting attacks.

Newer browsers support this header in the native XMLHttpRequest client (known as XMLHttpRequest Level 2). IE 8-9 support this through the XDomainRequest client, so you'll have to feature detect this if you want to support those browsers (grumble grumble). If you can't modify the server to emit this header, you may need to resort to your own proxy using a host that you can control to accept connections from salesforce.com and proxy the request to the destination server.

0

Well I found a way to do it. I have no idea how acceptable it is as far as Salesforce coding practises go, but it worked for me. I haven't included a mechanism to stop the poll, but in my full implementation I issue an HTTP POST that tells my server to abort the poll.

Page

<apex:page controller="longpollcontroller">
    <apex:form>
        <script>
        function doLongPoll() {
            Visualforce.remoting.Manager.invokeAction(
                '{!$RemoteAction.longpollcontroller.startLongPoll}',
                function (result, event) {
                    if (event.status) {
                        console.log(result); // show our results
                        doLongPoll(); // restart the poll
                    }
                }, {escape: false, timeout: 60000, buffer: false});
        }
        </script>
        <apex:outputPanel id="panel">
            <apex:commandButton onclick="doLongPoll();" value="Start Long Poll" rerender="panel" />
        </apex:outputPanel>
    </apex:form>
</apex:page>

Controller

public class longpollcontroller {

    @RemoteAction public static 
    String startLongPoll() {
        String strResult = '{"defaultResp":"startLongPoll called"}';

        try {
            HttpRequest req = new HttpRequest();

            req.setEndpoint('http://myLongPollURL');
            req.setMethod('GET');
            req.setTimeout(60000);

            Http http = new Http();
            HTTPResponse res = http.send(req);

            if (res.getStatusCode() == 200) {
                strResult = res.getBody();
            }
        }
        catch (CalloutException e) {
            strResult = '{"exception" : "' + e.getMessage() + '"}';
        }       

        return strResult;
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.