74

I am using nodejs and expressjs. I wonder if there is something like request.headers.protocol in the clientRequest object. I would like to build the baseUrl for the web links. So if the request was done via https I would like to keep https in all links.

    var baseUrl = request.headers.protocol + request.headers.host;
aartiles
  • 1,439
  • 4
  • 16
  • 31

9 Answers9

109

Edit: For Express, it's safer and recommended to use req.secure (as @Andy recommends below). While it uses a similar implementation, it will be safe for future use and it also optionally supports the X-Forwarded-Proto header.

That being said, for your use case it would be quicker to use Express' req.protocol property, which is either http or https. Note, however, that for outgoing links, you can just refer to //example.com/path, and the browser will use the current protocol. (See also Can I change all my http:// links to just //?)

For node Request object without Express:

It's in req.connection.secure (boolean).

Edit: The API has changed, for Node 0.6.15+:

An HTTPS connection has req.connection.encrypted (an object with information about the SSL connection). An HTTP connection doesn't have req.connection.encrypted.

Also (from the docs):

With HTTPS support, use request.connection.verifyPeer() and request.connection.getPeerCertificate() to obtain the client's authentication details.

Linus Thiel
  • 38,647
  • 9
  • 109
  • 104
  • 3
    Is this still available in the latest node 0.10 and up? – CMCDragonkai Feb 07 '14 at 14:25
  • 1
    Hm, can you verify this for later node versions like 0.8 and up, I cannot find anything of the sort in documentation. But it could be that I am reading in the wrong place. – Olga Mar 21 '14 at 15:44
  • This still exists in Node v5.x. – Ben Mar 13 '16 at 20:53
  • 2
    at least [when using express](http://expressjs.com/de/api.html#req.secure), one can rely on `req.secure` (as a boolean property) or likewise `'https' == req.protocol` – Frank N Jul 12 '16 at 13:47
  • 4
    I'm running NodeJs v11.5.0 and the request object does not contain a `.connection.encrypted` -- how can I tell now? – ekkis May 17 '19 at 21:04
  • 2
    This answer may be outdated. I'm running a nodejs server on aws w/ ssl and encrrypted is undefined – Trevor Wood Jul 02 '20 at 15:21
  • 6
    Try ``req.socket.encrypted``. In the most recent versions of Node.js, the ``.connection`` property was changed to a ``.socket`` property. https://nodejs.org/dist/latest-v12.x/docs/api/http.html#http_message_socket – Take-Some-Bytes Aug 10 '20 at 04:44
56

req.secure is a shorthand for req.protocol === 'https' should be what you looking for.

If you run your app behind proxy, enable 'trust proxy' so req.protocol reflects the protocol that's been used to communicate between client and proxy.

app.enable('trust proxy');

pronebird
  • 12,068
  • 5
  • 54
  • 82
  • oh right, confused with `require('url').parse(..).protocol` – caub Nov 19 '16 at 13:46
  • 5
    Nice call on mentioning `app.enable('trust proxy');` Not using this was causing an redirect loop. – docta_faustus Mar 21 '17 at 03:38
  • 3
    @Ben what does node v5.x have to do with this? Please read documentation for express 4.x (which is the latest by far): https://expressjs.com/en/4x/api.html#req.protocol – pronebird Mar 22 '17 at 11:23
11

For pure NodeJS (this works locally and deployed, e.g. behind Nginx):

function getProtocol (req) {
    var proto = req.connection.encrypted ? 'https' : 'http';
    // only do this if you trust the proxy
    proto = req.headers['x-forwarded-proto'] || proto;
    return proto.split(/\s*,\s*/)[0];
}
tjklemz
  • 1,170
  • 12
  • 19
9

You don't need to specify the protocol in URL, thus you don't need to bother with this problem.

If you use <img src="//mysite.comm/images/image.jpg" /> the browser will use HTTP if the page is served in HTTP, and will use HTTPS if the page is served in HTTPS. See the @Jukka K. Korpela explanation in another thread.

Community
  • 1
  • 1
Gerardo Lima
  • 6,467
  • 3
  • 31
  • 47
3

This worked for me:

req.headers['x-forwarded-proto']

Hope this helped,

E

  • 3
    Note that this will only work if your app is running behind a reverse proxy that sets this header — which is a good idea, but may not be the case especially in e.g. a local dev environment. (Also, keep in mind that if you're *not* behind a proxy a client could spoof the header, so be careful how you trust it.) – natevw Mar 06 '13 at 17:59
  • Also this in some cases gives you the ip not the http host! – Saud Alfadhli Aug 11 '13 at 22:05
  • I'm using OpenShift, and this is the correct answer for that service (req.secure and req.protocol don't work); just thought I'd mention in case someone else is too. – iangilman Aug 15 '17 at 20:24
2

This is what works for me:

getAPIHostAndPort = function(req, appendEndSlash) {
    return (req.connection && req.connection.encrypted ? 'https' : 'http') + '://' + req.headers.host + (appendEndSlash ? '/' : '');
}
Nico
  • 4,248
  • 1
  • 20
  • 19
  • 1
    `IncommingSocket` (what `req` actually is) no longer supports a `connection` property (https://nodejs.org/dist/latest-v16.x/docs/api/http.html#messageconnection). The replacement is `net.socket` and `net.socket` does not have an `encrypted` property either (https://nodejs.org/dist/latest-v16.x/docs/api/net.html#class-netsocket) – RavenHursT Mar 09 '22 at 20:04
  • @RavenHursT Have you found solution? Seems that express library is using deprecated property as well (https://github.com/expressjs/express/blob/8368dc178af16b91b576c4c1d135f701a0007e5d/lib/request.js#L307) – Somnium Nov 21 '22 at 09:53
  • Nope.. sorry. I stopped using `express` a while back and since use `koaJS` when building APIs... – RavenHursT Nov 21 '22 at 17:52
1

If you want to know whether request is http or https then use this in your code:

req.headers.referer.split(':')[0];

This will return whether req is http or https.

Skoua
  • 3,373
  • 3
  • 38
  • 51
Harsh
  • 69
  • 1
  • 2
  • 2
    it only works when users are redirect from the same site, when use visit the site by inputting domain in browser's nav bar directly, it would not work – DengSihan May 24 '21 at 05:29
1

If you are using request module and for example want to know what protocol does some www use, you can use: response.request.uri.protocol

request(YOUR_TARGET, function(error, response, body){
    if (error){
        console.log(error);
    }
    else {
        console.log(response.request.uri.protocol); // will show HTTP or HTTPS
    }
});

If you need user protocol then use request.headers.referer.split(':')[0]; just like @Harsh gave you.

b4rtekb
  • 136
  • 7
1

If you want to find the request protocol string: either http or (for TLS requests) https just use

 req.protocol

Express documentation: https://expressjs.com/en/4x/api.html#req.protocol

Spandan Joshi
  • 809
  • 10
  • 11