bootstrapping-microservices/chapter-3

app.get() always get called twice when requesting from Chrome/Firefox

Closed this issue · 5 comments

Test the sample codes (example-1) with a web browser (Chrome / Firefox) to get the video link (e.g. http://localhost:3000/video), Video is shown on browser as expected. However, the app.get() is actually called two times, which is unexpected.

This issue can be easily reflected on terminal console if one adds a console.log() line inside the app.get() function. For example:
app.get("/video", ( req, res) => {
reqcount++;
console.log( "reqcount="+reqcount);
... original example code...
});

The above change will prove that, for every request on the video link via a web browser, variable reqcount is increased twice.

The issue applies to video content only. If the sample code is modified to return a jpeg picture file (content type set to "image/jpeg"), the app.get() is called once, which is the expected behavior.

If one uses wget instead of web browser to get the video link (e.g. "$wget http://localhost:3000/video"), the app.get() is called once only, which is the expected behavior.

Any idea why ?

I think you'll find that it is invoked twice because one request is HEAD request and the next is the GET request.

Trying printing out req.method and you will probably see that.

Browsers often do a HEAD request first when requesting video to get information about the video before attempting to stream the entire thing.

It's an annoying behaviour of express that it puts HEAD requests and GET request through the GET handler.

This shouldn't be a problem for Chrome or Firefox (just confusing and annoying), but the code doesn't even work for Safari.

You can find more information on how to do video streaming on Safari on my blog post here:
https://www.the-data-wrangler.com/video-streaming-in-safari

I digged in req.rawheaders to find out the difference between Chrome's 1st and 2nd request:
1st request : Upgrade-Insecure-Requests
2nd request : normal content request

Chrome generates both requests when one enters 'http://localhost:3000/video". Then Express calls the same app.get() route twice because of the two requests. That explains why video is returned twice in this example. To truely avoid the problem, one need to respond to the Upgrade-Insecure-Rqeuests properly.

For wget, it doesn't generate the 'Upgrade-Insecure-Request' but simply issues a normal HTTP GET request.

Below is captured printout of req.rawheaders in the two requests sent from Chrome:

req.rawheaders in 1st request :
[
'Host',
'192.168.135.170:3000',
'Accept',
'text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8',
'Upgrade-Insecure-Requests',
'1',
'User-Agent',
'Mozilla/5.0 (X11; Ubuntu; Linux x86_64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Safari/605.1.15 Epiphany/605.1.15',
'DNT',
'1',
'Accept-Encoding',
'gzip, deflate',
'Accept-Language',
'en-hk,en;q=0.90',
'Connection',
'Keep-Alive'
]

req.rawheaders in 2nd request:
[
'Host',
'192.168.135.170:3000',
'Connection',
'close',
'Icy-Metadata',
'1',
'Accept',
'/',
'User-Agent',
'Mozilla/5.0 (X11; Ubuntu; Linux x86_64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Safari/605.1.15 Epiphany/605.1.15',
'DNT',
'1',
'Accept-Language',
'en-hk,en;q=0.90'
]

Thank you for suggesting the further reading !

If you think of any updates that would improve the code, please let me know!

@hkdev1999 Just letting you know I've started working towards a 2nd edition of Bootstrapping Microservices so I'm going to take this feedback into account.

If you have other feedback please reach out to me on ashley@codecapers.com.au.