According HTTP/1.1 the browsers should have two parallel requests per domain. It is very important to minimize requests in order to minimize the load time. Besides decreasing the load time, also important is to decrease the total bandwidth. In order to do it, there are several techniques.
Compact CSS and JS files
If possible, compact all css files in one file. The same applies for the JS files. In this way there will be only one request for CSS and one request for JS file.
Many times we need to use the same images in several places with different dimensions.
Do not use the same image and resize it with HTML. Instead, resize it once on the backend and server images with different dimensions. There are plenty of tools for this purpose. Even you can build your own.
Use sprites if possible
If possible use sprites to combine more images into one bigger. The total amount of image size will be the same, but you will reduce number of requests. This can be applied in rare cases usually when you have fixed size images like various toolboxes or similar. Putting images that can vary in a sprite is out of question.
In order to utilize browser cache and thus reduce the number of calls to the server, a http cache headers needs to be accompanied with the response for images, css and js files and probably other static data.
This header controls if the page should be cached or not. If it is cacheable, for how long in seconds from the time it was received. Until that time the browser will not make additional requests, meaning it saves bandwidth and also processing power on the server. Use if for less dynamic pages. If the page is more dynamic, then probably ETag is more appropriate. Note that if you test this by Chrome and you reload the same url again Chrome will not cache it! If you open the same url chrome will think something is not ok and will fetch the data from the resources not from the cache. In order to check it you need to open different url and then open the test url in different tab, in order to see what exactly is cached.
If Cache-Control is used then Expires tag is redundant. The difference is that Cache-Control is given in seconds, and Expires is given in a specific date time format when the cache will be invalidated. Until that time the browser will not make additional requests, meaning it saves bandwidth and also processing power on the server.
This tag only saves bandwidth but not processing power on the server. This tag needs to be validated on the server side meaning the headers are always sent. When the web server serves the page, also it returns ETag. If the browser needs the same page again, it will sent another request to the server containing the previous ETAG value. The server checks the ETAG value based on the generated request content (note that in this case the server must generate the content as usual) and if the ETag of the content (example md5) is the same as the ETag coming from the request then it will send HTTP 304 Not Modified without sending the actual body of the request. If the etag was different, the full content will be returned.
Similar to ETag, but instead Last-Modified is in date time format. If using ETag, Last-Modified will be redundant.
Edge Sides Include is a
markup language for dynamic web content assembly. It can be done in the reverse proxy. I am not sure how much this technique is used today.
Proxy cache – Varnish
Use reverse proxy cache like Varnish to decrease the load of the server and to improve the performance. Varnish Cache is a web application accelerator also known as a caching HTTP reverse proxy. You install it in front of any server that speaks HTTP and configure it to cache the contents. Varnish Cache is really, really fast. It typically speeds up delivery with a factor of 300 – 1000x, depending on your architecture. Varnish is very flexible for configuration. From it’s config file it is very easy to edit the headers, control the lifetime of the cache, control what to be cached.
This days almost every application has mobile version. Desktop version should be cached as one object, mobile version should be cached as different object. Just you need to include this config https://github.com/varnish/varnish-devicedetect/blob/master/devicedetect.vcl and set the “Vary” based on the “X-UA-Device” header. And you will have different caches for mobile version and desktop version (of course if you serve different contend for each of them by the server side)
Give it a try, use Varnish as a reverse proxy to gain sped. I am using it almost a year. I have never experienced a problems. We are caching the public pages. When the user makes a post, then Varnish passes the request to the apache. We are using this for login. When the user is logged in, it creates a cookie. The cookie tells Varnish not to cache the content when the cookie has value=1. With this, the cache is bypassed for logged in users, because the data is dynamic in that case.
About the performance. Now the web site has “Waiting Time” of around 50-60 milliseconds (not including connection time) for cached pages. Just to compare with google from the same computer, google search page needs around 160 milliseconds waiting time measured with Chrome. I am not saying the web site is faster than Google, but I am saying that the backend returns the content more quickly.