I'm developing a web application that manages a large amount of images, stores and resizes them.
the request of an image is something like: domain:port/image_id/size
The server takes the image_id and if there isn't yet an image of such size it creates it and stores it on filesystem.
So everything is ok and the server is running but I need to cache those images in browser for at least one day to reduce the server bandwidth consumption.
I did several tests but nothing seems to work.
Here is the code I use to make the response header:
response.writeHead(304, {
"Pragma": "public",
"Cache-Control": "max-age=86400",
"Expires": new Date(Date.now() + 86400000).toUTCString(),
"Content-Type": contentType});
response.write(data);
response.end();
I also tried with response status 200. contentType is always a mime type like "image/jpg" or "image/png" data is the bytes buffer of the image.
Any advice? Thanks a lot.
live long and prosper,
d.
I did a lot of tests and I came out with a solution that seems pretty good to manage this caching problem.
Basically what I do is getting the request and check for the request header named "if-modified-since". If I find it and the value (it is a date) is the same as the modified date of the file, the response will be a 304 status with no content. If I don't find this value or it's different from the modified date of the file, I send the complete response with status 200 and the header parameter for further access by the browser.
Here is the complete code of the working test I did:
with "working" I mean that the first request get the file from the server while the next requests get a 304 response and don't send content to the browser, that load it from local cache.
var http = require("http");
var url = require("url");
var fs = require('fs');
function onRequest(request, response) {
var pathName = url.parse(request.url).pathname;
if (pathName!="/favicon.ico") {
responseAction(pathName, request, response);
} else {
response.end();
}
}
function responseAction(pathName, request, response) {
console.log(pathName);
//Get the image from filesystem
var img = fs.readFileSync("/var/www/radar.jpg");
//Get some info about the file
var stats = fs.statSync("/var/www/radar.jpg");
var mtime = stats.mtime;
var size = stats.size;
//Get the if-modified-since header from the request
var reqModDate = request.headers["if-modified-since"];
//check if if-modified-since header is the same as the mtime of the file
if (reqModDate!=null) {
reqModDate = new Date(reqModDate);
if(reqModDate.getTime()==mtime.getTime()) {
//Yes: then send a 304 header without image data (will be loaded by cache)
console.log("load from cache");
response.writeHead(304, {
"Last-Modified": mtime.toUTCString()
});
response.end();
return true;
}
} else {
//NO: then send the headers and the image
console.log("no cache");
response.writeHead(200, {
"Content-Type": "image/jpg",
"Last-Modified": mtime.toUTCString(),
"Content-Length": size
});
response.write(img);
response.end();
return true;
}
//IF WE ARE HERE, THERE IS A PROBLEM...
response.writeHead(200, {
"Content-Type": "text/plain",
});
response.write("ERROR");
response.end();
return false;
}
http.createServer(onRequest).listen(8889);
console.log("Server has started.");
Of course, I don't want to reinvent the wheel, this is a benchmark for a more complex server previously developed in php and this script is a sort of "porting" of this PHP code:
http://us.php.net/manual/en/function.header.php#61903
I hope this will help!
Please, if you find any errors or anything that could be improved let me know!
Thanks a lot, Daniele