1
votes

i tried to cache a json response from an api request using the Etag. I'm calling something like this http://localhost:3000/api/config and getting:

Response Headers:
Cache-Control:public, max-age=31557600
Connection:keep-alive
Content-Length:11
Content-Type:application/json; charset=utf-8
Date:Wed, 13 May 2015 11:41:52 GMT
ETag:"94d52736bcd99b1ac771f13b1bbdf622"
X-Powered-By:Express

Resonse: {id: 1}

I expected the browser to cache the response and to send the Etag with the next request triggert by "f5". But this isn't the case.

Request Headers 2nd request:
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8
Accept-Encoding:gzip, deflate, sdch
Accept-Language:de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
Cache-Control:no-cache
Connection:keep-alive
Host:localhost:3000
Pragma:no-cache
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36

So is it impossible to cache pure json response, getting by a direct api requests?
Or do i miss something.

The api is an node js test implemantation done with express:

router.get('/config', function(req, res) {
    var eTag = crypto.createHash('md5').update(JSON.stringify(config)).digest('hex');
    res.setHeader('ETag', '"' + eTag + '"');
    res.setHeader('Content-Type', 'application/json');
    res.setHeader('Cache-Control', 'public, max-age=31557600');
});

Testet with chrom(42.x) and firefox(37.x)

Thx for response.

3
Yes you can cache JSON responses. At first glance it seems like a browser side issue. You shouldn't be sending pragma: no-cache in the request headers unless you disabled cache in chrome debugger tools or elsewhere in your browser settings. How are you issuing this request?Andrew Lavers
I just call the api route, using the browser url bar. I also tried to call the route using a script tag like <script src="localhost:3000/api/config"></script> returning a javascript object var config = {...}.Lukas Bonzelett
I read that it should be possible with an ajax request but i need a direct call.Lukas Bonzelett
I found a hint, i used res.end() to send response maybe thats the problem, i will try that again on monday.Lukas Bonzelett

3 Answers

1
votes

Hi this code seems to work for me:

router.get('/config', function(req, res) {
    var eTag = crypto.createHash('md5').update(JSON.stringify(config)).digest('hex');

    if (req.headers['if-none-match'] && req.headers['if-none-match'] === '"' + eTag + '"') {
        res.status(304);
        res.end();
    } else {
        res.setHeader('ETag', '"' + eTag + '"');
        res.setHeader('Content-Type', 'application/json');
        res.setHeader('Cache-Control', 'public, max-age=31557600');
        res.send(JSON.stringify(config));
    }
});

Calling the api using browser url bar http://localhost:3000/api/config

0
votes

Looks like you might be using chrome. Chrome should include the following header in the request after "f5":

If-None-Match:"94d52736bcd99b1ac771f13b1bbdf622"

If you don't see this, check the chrome settings / General and make sure that "Disable cache (while DevTools is open) is not checked:

Disable cache not checked in Chrome dev tools

0
votes

Using jQuery we can use the ifModified option:

$.ajax({
   type: "GET",
   ifModified: true,
   url: "http://localhost:3000/api/config"
}).then(function(data) {
   . . .
});