سؤال

I am using nodejs and express to redirect all http requests to https. Usually the browser is successfully redirected to https but its often possible to type in an url with http (or without any protocol) that appears not to redirect: the page loads but the url bar stays as mysite.com without https or a lock icon.

This can happen in both Chrome and IE. When this happens, the Chrome network logger shows a mixture of 304 and 302 responses. Does this mean that there is some sort of caching causing the browser to not redirect to https?

   var express = require('express'),
        path = require('path'),
        http = require('http'),
        https = require('https'),
        fs = require ('fs');

    var app = express();

    var options = {
      key: fs.readFileSync('cert/rsa.key'),
      cert: fs.readFileSync('cert/rsa.crt'),
      ca: fs.readFileSync('cert/sub.class1.server.ca.pem')
    };

    function requireHTTPS(req, res, next) {
        if (!req.secure) {
            return res.redirect('https://' + req.get('host') + req.url);
        }
        next();
    }

    app.use(requireHTTPS);

    app.use('/path/html', express.static(rootFolder + 'path/html'));
    app.use('/path/fonts', express.static(rootFolder + 'path/fonts'));

    app.all('*', function (req, res) {
        res.sendfile('index.html', { root: rootFolder + 'path/' });
    })

    https.createServer(options, app).listen(443);
    http.createServer(app).listen(80);

Edit - tips for reproducing

I am using the recommended https redirect method for express so I suspect many sites suffer from this problem without realising it. For Chrome on W7, I always see a correct redirect on first visit or when I use the url auto-complete or the omnibox drop down. However if I type in the url or hand edit an auto-complete, then I can reliably see a failed redirect:

  1. Delete chrome browser cache

  2. type in your url http://_mysite.com and hit enter => correct redirect to https://_mysite.com

  3. create a new tab, type your url until it auto-completes and hit enter => correct redirect to https://_mysite.com

  4. create a new tab, as 3. but before hitting enter, edit the auto-complete by deleting the last character and retyping, hit enter => page renders but url stays at http://_mysite.com with no lock symbol.

Server logs show the root static page is not fetched, only some parts of the page content. All get requests to the page content are https despite the browser not reporting this.

هل كانت مفيدة؟

المحلول 2

Here is an attempt to answer my own question. By forcing a 307 response, I am seeing a reliable redirect with no caching. However I'm not sure how "correct" this is and whether it can be confidently used without breaking in future browser versions.

function requireHTTPS(req, res, next) {
    if (!req.secure) {
        return res.redirect(307, 'https://' + req.get('host') + req.url);
    }
    next();
}

نصائح أخرى

When you do this:

return res.redirect('https://' + req.get('host') + req.url);

Express will return a 302.

However, that code may not be executed, because of caching (as you suspected).

If your browser previously cached the page, then the browser will send a conditional HTTP request, basically telling Express, “send me the page, but only if it’s changed.” If the page has not changed, Express will send a 304 Not Modified.

Clear your browser’s cache and try again, or make some small modification to the page.

Under the hood, Express uses node-fresh to decide whether to send a 304 response. The logic is fairly simple and can be seen here. One of the factors it checks is the page’s ETag (a hash of the page body). So any small change to the page will force your browser to refresh it. Alternatively, you can set Cache-Control: no-cache if you want to force the browser to get a fresh copy of the page every time.

You can also disable ETags:

app.disable('etag')

Of course this might lead to more traffic that the conditional requests and 304 responses were designed to reduce.

Here is what I use to force HTTPS.

requireHTTPS = function(req, res, next){
  if (req.secure)  return next();
  res.redirect("https://" + req.headers.host + req.url);  
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top