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/updatedfavicon
, 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
offavicon
in yourhtml
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:
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
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
Your issue could be related to
- Browser already has a cached favicon hence, does not request it
- You are not serving the favicon properly in server.js
- 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:
- Opera 10
- Opera 9.64
- Firefox 3.5
- IE 6
- IE 7
- IE 8
- 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
Open Url in New Tab or Reuse Existing One Whenever Possible
:Touch CSS Pseudo-Class or Something Similar
How to Change the Background Image of Div Using JavaScript
How to Combine Jquery Animate with CSS3 Properties Without Using CSS Transitions
Tool for Checking Unused CSS Selectors
Transforms Are Added...Endlessly
Installing a Local Module Using Npm
Google Chrome Console.Log() Inconsistency with Objects and Arrays
Keydown Simulation in Chrome Fires Normally But Not the Correct Key
How to Split a Long Array into Smaller Arrays, with JavaScript
Set a Callback Function to a New Window in JavaScript
How to Limit Options Selected in a HTML Select Box
The Purpose of Starting an Initial Comment with /*! in JavaScript and CSS Files
Blinking/Flickering with Jqm and Phonegap on Android
Changing Background Color of Div on Scroll
Difference Between Throttling and Debouncing a Function
Is There a Max Number of Arguments JavaScript Functions Can Accept