req.headers is Node's lower-cased header object; req.get(name) ignores case and understands the Referrer/Referer spelling mess. req.is(type) reports what the body claims to be.
app.get('/hdr', (req, res) => res.json({
referrer: req.get('Referrer'), // matches the misspelled Referer header
isJson: req.is('json'), // null when the request has no body
accepts: req.accepts(['html', 'json']), // best match, or false
lang: req.acceptsLanguages(['en', 'de'])
}));$ curl -s .../hdr -H "Accept: application/json;q=0.9, text/html;q=0.8" \
-H "Accept-Language: de-DE,de;q=0.9" -H "Referer: https://example.com/list"
{"referrer":"https://example.com/list","isJson":null,"accepts":"json","lang":"de"}req.is('json') returned null, not false, even though the request carried a JSON content type: it answers null when there is no body, so a GET always does. The singular Express 4 24,430 spellings acceptsCharset, acceptsEncoding and acceptsLanguage are gone; only the plural forms remain.
Unconfigured, req.ip is the socket's remote address and req.protocol whatever the socket is — behind a load balancer, both describe the proxy. Proxies forward the truth in X-Forwarded-For, X-Forwarded-Proto and X-Forwarded-Host, but anyone can send those headers, so Express ignores them until you declare how many hops you control: app.set('trust proxy', 1), a named subnet such as 'loopback', or a CIDR block.
That is a hop count, not a switch. req.socket.remoteAddress is hop 0; Express walks X-Forwarded-For right to left, discarding as many entries as you trust, and the first untrusted address becomes req.ip. Below, one request carrying X-Forwarded-For: 203.0.113.9, 70.41.3.18 and X-Forwarded-Host: api.example.com is replayed against three settings.
| trust proxy | req.protocol | req.hostname | req.ip | req.ips |
|---|---|---|---|---|
| unset | http | localhost | ::1 | [] |
| 1 | https | api.example.com | 70.41.3.18 | 70.41.3.18 |
| 2 | https | api.example.com | 203.0.113.9 | both, in order |
Count carefully. Too low and every client shares the last proxy's address, so a per-IP rate limiter (Rate Limiting) throttles all your users at once; too high — true trusts the leftmost entry unconditionally — and a client can impersonate anyone. A missing trust proxy also leaves req.protocol reporting http under TLS, breaking secure cookies.