How to Prevent an Http Request Just for a Favicon

How to prevent an HTTP request just for a favicon?

Killer Solution in 2020

This solution necessarily comes nine years after the question was originally asked, because, until fairly recently, most browsers have not been able to handle favicons in .svg format.

That's not the case anymore.

See: https://caniuse.com/#feat=link-icon-svg



1) Choose SVG as the Favicon format

Right now, in June 2020, these browsers can handle SVG Favicons:

  • Chrome
  • Firefox
  • Edge
  • Opera
  • Chrome for Android
  • KaiOS Browser

Note that these browsers still can't:

  • Safari
  • iOS Safari
  • Firefox for Android

Nevertheless, with the above in mind, we can now use SVG Favicons with a reasonable degree of confidence.



2) Present the SVG as a Data URL

The main objective here is to avoid HTTP Requests.

As other solutions on this page have mentioned, a pretty smart way to do this is to use a Data URL rather than an HTTP URL.

SVGs (especially small SVGs) lend themselves perfectly to Data URLs, because the latter is simply plaintext (with any potentially ambiguous characters percentage-encoded) and the former, being XML, can be written out as a long line of plaintext (with a smattering of percentage codes) incredibly straightforwardly.



3) The entire SVG is a single Emoji

N.B. This step is optional. Your SVG can be a single emoji, but it can just as easily be a more complex SVG.

In December 2019, Leandro Linares was one of the first to realise that since Chrome had joined Firefox in supporting SVG Favicons, it was worth experimenting to see if a favicon could be created out of an emoji:

https://lean8086.com/articles/using-an-emoji-as-favicon-with-svg/

Linares' hunch was right.

Several months later (March 2020), Code Pirate Lea Verou realised the same thing:

https://twitter.com/leaverou/status/1241619866475474946

And favicons were never the same again.



4) Implementing the solution yourself:

Here's a simple SVG:

<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16">

<text x="0" y="14">lt;/text>
</svg>

And here's the same SVG as a Data URL:

data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2016'%3E%3Ctext%20x='0'%20y='14'%3E%3C/text%3E%3C/svg%3E

And, finally, here's that Data URL as a Favicon:

<link rel="icon" href="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2016'%3E%3Ctext%20x='0'%20y='14'%3E%3C/text%3E%3C/svg%3E" type="image/svg+xml" />


5) More tricks (...these are not your parents' favicons!)

Since the Favicon is an SVG, any number of filter effects (both SVG and CSS) can be applied to it.

For instance, alongside the White Unicorn Favicon above, we can easily make a Black Unicorn Favicon by applying the filter:

style="filter: invert(100%);"

Black Unicorn Favicon:

<link rel="icon" href="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2016'%3E%3Ctext%20x='0'%20y='14'%20style='filter:%20invert(100%);'%3E%3C/text%3E%3C/svg%3E" type="image/svg+xml" />

How to prevent the browser from asking for the favicon?

No, I don't think there is. From Wikipedia:

Most web browsers do not require any HTML to retrieve a favicon that conforms to the de facto file name and type (favicon.ico) located in the web site's root. If no favicon link is detected upon HTML page load completion and no previous site visits are recorded in the browser's history, a favicon.ico is requested automatically.[8]

The only thing you could do is explicitly point the browser to a different location (that for example could return a 204 no content)

<link rel="shortcut icon" href="http://www.example.com/my_empty_resource" />

what's the smallest proper answer to http requests for favicon.ico

According to RFC 2616, the shortest valid response would be

HTTP/1.0 404 <CRLF>
<CRLF>

There should be a space between 404 and the line terminator, actually separating the status code from the status reason message (which is an empty string in this case). This might not be strictly required, but I doubt saving a single byte is worth the minor deviation from the RFC.

no request for favicon

I played around with your repo code and did some changes to see if I can serve my favicon or not. I found out some strange stuff:

  • favicon serving is tricky and mysterious (my point of view)
  • Chrome used to have a bug or might still have relating to favicon (Google please, there are many results)
  • Seems like browser caches favicon, force refresh and different methods used to make browser get the new/updated favicon, see here
  • I found that once Chrome browser is served the favicon then in the subsequent request, there is no more favicon request. Not until you change the href of favicon in your html file and that forces browser to make a fresh request.

I copied bit/pieces of your code to reproduce the issue and got it working. I decided to serve the favicon differently see below:

server.js

if(req.url.match("/requestFavicon") ){
var img = fs.readFileSync('public/favicon.ico');
res.writeHead(200, {'Content-Type': 'image/x-icon' });
res.end(img, 'binary');
}

index.html

<link rel="shortcut icon" type="image/x-icon" href="/requestFavicon"/>

Did a nodemon server.js and used Chrome browser to make http://192.168.1.18:8080 request. The terminal showed the following:

GET request for /
GET request for /requestFavicon

And the favicon.ico (tiny vehicle .ico taken from here) displayed in the browser see below:

Sample Image

After the above favicon was displayed, any subsequent http://192.1668.18:8080 produced no request for favicon but, only displayed the following request in terminal of nodejs

GET request for /

Similarly no favicon related request in the browser developer tool network tab.

At this point, I assumed that the browser has cached it and does not request at all because it already has it. So I googled and came across this SO question to force refresh favicon request. So, let's change the favicon href in the index.html (and server.js) and retry

<link rel="shortcut icon" type="image/x-icon" href="/updatedRequestFavicon"/>

Now retry access http://192.168.1.18:8080 and watch for nodejs terminal as well as chrome developer console and I get the following:

GET request for /
GET request for /UpdatedRequestFavicon

Sample Image

Now I want to totally change the favicon and put a new one. I added this one updated the server.js and refreshed the browser. Surprisingly no console log in nodejs (for new favicon), no request in browser developer tools newtork console (so served the cached value then).

To force the browser to get the new favicon, I want to change the href of favicon in index.html and and update the server.js with new href and then see if brwoser gets forced to request for updated favicon or keep using the cached one.

<link rel="shortcut icon" type="image/x-icon" href="/NewFavicon"/>
if(req.url.match("/NewFavicon") ){
var img = fs.readFileSync('public/favicon_new.ico');
res.writeHead(200, {'Content-Type': 'image/x-icon' });
res.end(img, 'binary');
}

Changed. Changes reloaded by nodemon, refresh the browser and here is the result:

GET request for /
GET request for /NewFavicon

Sample Image

Your issue could be related to

  1. Browser already has a cached favicon hence, does not request it
  2. You are not serving the favicon properly in server.js
  3. Something else

If you want to test my code, feel free, here is the server.js

var http = require('http');
var fs = require('fs');
var path = require('path');

var server = http.createServer(function(req, res) {
// Log req Method
console.log(`${req.method} request for ${req.url}`);
//res.writeHead(200);
//res.end('index.html');

// Serve html, js, css and img
if ( req.url === "/" ){
fs.readFile("index.html", "UTF-8", function(err, html){
res.writeHead(200, {"Content-Type": "text/html"});
res.end(html);
});
}

if(req.url.match("/NewFavicon") ){
console.log('Request for favicon.ico');

var img = fs.readFileSync('public/favicon_new.ico');
res.writeHead(200, {'Content-Type': 'image/x-icon' });
res.end(img, 'binary');

//var icoPath = path.join(__dirname, 'public', req.url);
//var fileStream = fs.createReadStream(icoPath, "base64");
//res.writeHead(200, {"Content-Type": "image/x-icon"});
//fileStream.pipe(res);
}
});
server.listen(8080);

Here is index.html

<!DOCTYPE html>
<html>
<head>
<title>nodeCAST</title>
<link rel="shortcut icon" type="image/x-icon" href="/NewFavicon"/>
<!--<link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon">
<link rel="icon" href="img/favicon.ico" type="image/x-icon">-->
</head>
<body>
<p>I am the index.html</p>
</body>
</html>

I placed the favicon.ico under /public directory. Good luck.

EDIT

Tested with Chrome Browser Version 47.0.2526.111 m

Node v4.2.4

Prevent favicon.ico from making a second request - Node.js

You're not supposed to call next when you want to respond to a request. Generally, it's not valid to writeHead() and then call next. Most middleware expects to work with a response that has not written to the network yet.

The reason your "stupid favicon" middleware runs is that you're calling it it by invoking next in the first one. You need to res.writeHead() and res.end() OR just call next.

function(req, res, next){
if (req.url === '/favicon.ico') {
res.writeHead(200, {'Content-Type': 'image/x-icon'} );
res.end(/* icon content here */);
} else {
next();
}
}

Alternatively, just use the builtin favicon middleware, which does important things like setting proper Cache-Control headers.

Will browsers request /favicon.ico or link first?

I did the test suggested above. I placed a /favicon.ico in the root of a domain, and a link, and fired up the page in:

  1. Opera 10
  2. Opera 9.64
  3. Firefox 3.5
  4. IE 6
  5. IE 7
  6. IE 8
  7. Safari 4

They all showed the icon loaded with <link rel="shortcut icon" href="http://cdn.site.com/favicon.ico"> (located on an external server). I checked access.log, and there were no requests to /favicon.ico!

I then commented out the <link>, checked again in all browsers, and they showed the /favicon.ico icon and corresponding entries in access.log.



Related Topics



Leave a reply



Submit