In a perfect world, developers would never need to know how a request go to their app. But we live on the Internet, where end-to-end protocols are used to transport messages across networks that are point-to-point, not end-to-end. Each point is represented by an intermediate device of diverse behavior that interacts with requests (and responses) in different ways.
Some are transparent and do not modify data developers need. Some are not, by design and necessity, and inadvertently introduce challenges for developers in retrieving that data.
The most common example of this reality is associated with load balancers/proxies.
Load balancers and proxies can – and by default do in modern architectures – make modifications to network characteristics that can frustrate developers. Many apps and services need to know the original client IP address from which a request came. Fraud-detection, bot identification, tracking, identity, and other needs drive this requirement.
The problem is that proxies/load balancers often replace that IP address with their own. This is an architectural by-product of load balancing and full-proxies as well as some security-related application services. This configuration facilitates the need for optimization, isolation, and supports emerging architectures like those based on containers to enable intra-container networking to operate without the constraints placed on public-facing networking.
That means that services and applications inside the application infrastructure are not receiving the original client IP address, but rather the IP address of the proxy performing ingress routing or load balancing.
This is not a new problem. This has been an issue for developers for many years. The resolution remains the same: proxies can be configured to pass on the original client IP address via HTTP headers. Many do this by default, and though it is not an official standard it is a best practice and a de facto standard to use the custom X-Forwarded-For HTTP header.
What remains, then, is for developers to extract that value in the event they need the original client IP address.
Which brings me to the focus of this post, which is getting the value of X-Forwarded-For from within node.js.
It turns out that this is fairly straightforward. Like most languages for which HTTP is a staple protocol, Node.js parses out HTTP and provides access to its headers as an array. Unlike those old-school structured languages (I’m looking at you C/C++) grabbing an HTTP header from that array is as simple as knowing what it’s called.
The request object created by a successful parse of an incoming HTTP request contains an array referenced as “headers.” To extract a specific header, simply index the array with the name of that header, a la: request.headers[“X-Forwarded-For”].
That said, the use of “X-Forwarded-For” is not mandated by any specification or standard. It’s a best practice and, of course, it’s polite to use it, but many proxies and frameworks use other custom headers in which to forward the same information.
This is a great opportunity to talk to the networking team and find out what HTTP header to use. Or, if the thought makes you queasy, I encourage you to check out this Node.js package called “forwarded-for” on GitHub that seeks out the original client IP address in known locations based on a variety of proxies. As an added benefit, the module gracefully falls back to returning the client address.
Because it’s open source, if your specific custom HTTP header isn’t included, you can always add it in – and don’t forget to contribute back!