Dominic Lovell

Caching dynamic client requests (eg: JSONP with jQuery or AngularJS)

Blog Post created by Dominic Lovell Employee on Jan 27, 2016

Dealing with unique client requests can often pull in dynamic content from different sources, but at the same time client frameworks use unique callback parameters that must be included in the response body, which then negate any opportunity to cache those responses. Here I talk about what JSONP is, and a potential way you can still cache on the edge yet provide unique content back to the client to handle the response.

 

JSONP is a great way to pull content from third party sources, allowing you to integrate any number of services and widgets into your site. JSONP resources allow you to specify a callback parameter in the request, which is a function name that will wrap the response, so that your function get called on the client, and your code can decide what to do with the data, such as display it or do some additional calculations.

 

Typically, you have some endpoint and response data such as:

 

https://api.mysite.com/weather/season.json?country=Australia

{
     "season"   : "Summer",
     "country"  : "Australia"
}



 

With JSONP, we might access the same resource and pass a callback parameter:

 

https://api.mysite.com/weather/season.json?callback=my_function&country=Australia

my_function({
     "season"   : "Summer",
     "location"  : "Australia"
})



 

So here, the response is wrapped in my callback function.

 

Then on my site, I could have a function to do something with the data:

<div id="weather"></div>
<script src="https://api.mysite.com/weather/season.json?callback=my_function&country=Australia"></script>
<script>
function my_function(json_data){
  document.getElementById('weather').innerHTML= 'It is ' + json_data['season'] + ' in ' + json_data['country'];
}
</script>



 

Which would inject It is Summer in Australia to the weather div based on the data from the endpoint.

 

This works fine when the callback is static such as the example above, however the problem arises when you use frameworks such as jQuery or Angular which create the callback name for you on the fly, so that it can process any success handlers you specify.

 

Here's a jQuery example:

 

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<script>
$.ajax({
    url: "http://query.yahooapis.com/v1/public/yql",
    // The name of the callback parameter, as specified by the YQL service
    jsonp: "callback",
    // Tell jQuery we're expecting JSONP
    dataType: "jsonp",
    // Tell YQL what we want and that we want JSON
    data: {
        q: "select title,abstract,url from search.news where query=\"cat\"",
        format: "json"
    },
    // Work with the response
    success: function( response ) {
        console.log( response ); // server response
    }
});
</script>




If we take a look at the request that gets generated, the callback is a unique parameter, specific to this function call. This way, if you make multiple ajax calls, jQuery knows which function is bound to which success handler. This causes all our client requests to be unique however, and does not let us cache the request, as each response includes the unique function name within the response body.

Screen Shot 2016-01-28 at 13.58.55.png

Given we have this unique parameter in the request, how we cache this at the edge, yet still have the response include the callback in the response?

 

The answer is using advanced techniques that combines ESI and response construction at the edge!

 

Screen Shot 2016-01-28 at 14.45.42.png

 

 

Here's the technique we use:

 

  1. The client framework generates a unique callback parameter
  2. The edge server then strips the callback parameter and stores this in a variable from the forward request, and stores this in a variable. The edge will send the stripped request to the origin (this would only occur if the item wasn't in cache already)
  3. The origin responds with the response specific to this endpoint and other parameters, which is a cacheable resource.
  4. The edge server when takes the response from the origin, and does the following:
    1. Puts the item from the origin server in cache, which does not include the callback parameter from the original request
    2. Takes the variable stored from step 2, and constructs a response, including the payload from step 3
    3. Sends the client the newly constructed response which includes the unique parameter in the body and the cacheable payload from the origin

 

By stripping the parameter, issuing a forward request, and constructing a dynamic response at edge, we are able to ensure the origin offload continues, yet each client response receives the unique response it requires to execute the JSONP callback function.

 

These techniques require some advance configuration, so if this is something you require, you should speak with your Akamai representative to see if this is achievable on your account.

 

If you have any further questions, please feel free to reach out to me, or your Akamai account representative. I work within the Advanced Solutions and Services team to provide assessments for customers, to help them address performance concerns, anywhere from an end to end assessment across the full stack, to something much lower level as an deep dive that tackles improving individual page speed metrics. For more information contact consulting@akamai.com.

Outcomes