675

Let's say my sample URL is

http://example.com/one/two

and I say I have the following route

app.get('/one/two', function (req, res) {
    var url = req.url;
}

The value of url will be /one/two.

How do I get the full URL in Express? For example, in the case above, I would like to receive http://example.com/one/two.

Syscall
  • 19,327
  • 10
  • 37
  • 52
Chris Abrams
  • 39,732
  • 19
  • 51
  • 57
  • 15
    FYI you can inspect the request object and look through but I am a hypocrite and found it on here. – King Friday Jan 07 '17 at 00:00
  • 3
    I have created: [Request: Introduce a `req.completeURL()` method · Issue #4697 · expressjs/express](https://github.com/expressjs/express/issues/4697) for this. – Peter V. Mørch Sep 12 '21 at 05:43

21 Answers21

967
  1. The protocol is available as req.protocol. docs here

    1. Before express 3.0, the protocol you can assume to be http unless you see that req.get('X-Forwarded-Protocol') is set and has the value https, in which case you know that's your protocol
  2. The host comes from req.get('host') as Gopal has indicated

  3. Hopefully you don't need a non-standard port in your URLs, but if you did need to know it you'd have it in your application state because it's whatever you passed to app.listen at server startup time. However, in the case of local development on a non-standard port, Chrome seems to include the port in the host header so req.get('host') returns localhost:3000, for example. So at least for the cases of a production site on a standard port and browsing directly to your express app (without reverse proxy), the host header seems to do the right thing regarding the port in the URL.

  4. The path comes from req.originalUrl (thanks @pgrassant). Note this DOES include the query string. docs here on req.url and req.originalUrl. Depending on what you intend to do with the URL, originalUrl may or may not be the correct value as compared to req.url.

Combine those all together to reconstruct the absolute URL.

  var fullUrl = req.protocol + '://' + req.get('host') + req.originalUrl;
Peter Lyons
  • 142,938
  • 30
  • 279
  • 274
  • Thanks - I ended up running into where some servers were on a different port than 80. – Chris Abrams Apr 23 '12 at 19:45
  • Can't all the headers be manipulated? So you can't depend on it to be correct? – dave Dec 19 '12 at 17:21
  • 3
    @dave a client can send whatever headers it wants (as well as whatever URL, port, random non-HTTP garbage), however, at some point bogus or inaccurate headers will simply cause the protocol to fail. For example, in a virtual host environment, an incorrect "host" header will display a completely different web site. In the case of X-Forwarded-Protocol, that is usually not send by the actual client (browser) but by the reverse proxy (nginx/varnish/apache/whatever) that is serving HTTPS in front of your application. – Peter Lyons Dec 19 '12 at 18:25
  • You missed the port section, you can get it by using: app.get('port') – Diosney Jan 02 '14 at 04:39
  • @diosney bullet 3 addresses the port. AFAIK `app.get("port")` will return undefined unless you have explicitly done an `app.set("port")`. There's no built-in functionality there. It's just a convenience key/value store. – Peter Lyons Jan 02 '14 at 17:19
  • The browser sends those in the "Authorization" request header in this format. https://en.wikipedia.org/wiki/Basic_access_authentication#Client_side You should be able to find npm modules to decode the simple format it uses. – Peter Lyons Apr 11 '14 at 14:29
  • when you use XHR.open(method,url,true,user,pass) is actually sends them in the url 'http://user:pass@host.com:8080/p/a/t/h?query=string#hash' – Code Uniquely Nov 27 '14 at 10:16
  • Is original URL just the same as req.url as long as req.url hasn't been changed? – CMCDragonkai Apr 19 '15 at 12:31
  • Does req.url actually change across the middleware? I'm creating a middleware and I need access to the original URL, but the middleware is framework independent right now. – CMCDragonkai Apr 19 '15 at 12:32
  • 23
    The `host` parameter in the request headers can be spoofed. There's a possible "host header attack" if using the `res.host` this way. In the Django framework they have an 'allowed hosts' variable that is used to prevent such attack. I use a configuration variable that is my `root_url` which can be added to the `req.url` for completion. About the attack: http://www.skeletonscribe.net/2013/05/practical-http-host-header-attacks.html – Amir Eldor Sep 19 '15 at 15:04
  • For browsers other than Chrome you can also use `req.socket.localPort` or `req.socket.remotePort` depending on what you need exactly. But if there are proxies involved I am not sure what will happen. – mixture May 08 '16 at 20:22
  • 2
    If you want to add `req.originalUrl` without parameters, simply do `req.originalUrl.split("?").shift()`. Source: https://stackoverflow.com/a/32118818/2037431 – Marcos Pereira May 15 '18 at 12:03
  • Thanks it helps me. Before i do not know how to use window object and after reading this answer i know to use it either in response or request object – Faris Rayhan Jun 28 '18 at 03:29
  • What about proxied requests? – Danosaure Jan 18 '19 at 15:57
  • 2
    Express 4.x strips the port from `req.host`, `req.hostname`, and `req.get('host')`. Undocumented, but works, is to access `req.headers.host` directly. – Jonathan Dec 01 '19 at 21:54
  • Please note with this recommendation that relying on both req.host and req.get('host') can introduce security issues – monokrome May 27 '20 at 18:16
  • The "Host" header is not supported in HTTP 2. You might want to consider using `req.host` or `req.hostname` and `server.address().port` for compatibility. – undefined Sep 18 '21 at 11:49
169

Instead of concatenating the things together on your own, you could instead use the node.js API for URLs and pass URL.format() the informations from express.

Example:

var url = require('url');

function fullUrl(req) {
  return url.format({
    protocol: req.protocol,
    host: req.get('host'),
    pathname: req.originalUrl
  });
}
Randy
  • 9,419
  • 5
  • 39
  • 56
Michael Weibel
  • 2,857
  • 3
  • 23
  • 25
  • 4
    In my case the `req.get('host')` returns only the *hostname* part, not the port. Don't know why, but now I gather the port number from the settings, and use the `hostname` field, instead of `host`. – maxkoryukov Aug 03 '16 at 00:57
  • 1
    Instead of `pathname`, I think you mean `path`. Which includes search/querystring – Félix Sanz Jan 12 '17 at 20:39
  • 4
    This doesn't work for URL's that have a query string. – Keith Feb 13 '18 at 17:31
  • I find this URL object useful, so if you could have a query string in your URL you could set it up by combining it with the answer from Peter Lyons, eg: `const url = new URL(req.protocol + '://' + req.get('host') + req.originalUrl)` – R Jones Oct 23 '20 at 13:59
  • 4
    `url.format` is now deprecated. – Michael Fry Sep 21 '21 at 20:10
  • yes, meanwhile you'd use https://developer.mozilla.org/en-US/docs/Web/API/URL - feel free to update the answer / give a new answer. – Michael Weibel Sep 23 '21 at 06:16
  • This, as most answers here (if not all of them) is wrong since it ignores the port. – Manuel Astudillo Dec 01 '21 at 03:25
42

In 2022

The above answers are working fine but are not preferred by the Documentation because url.parse is now legacy so I suggest you to use new URL() function if you want to get more control over url.

Express Way

You can get Full URL from the below code.

`${req.protocol}://${req.get('host')}${req.originalUrl}`

Example URL: http://localhost:5000/a/b/c?d=true&e=true#f=false

Fixed Properties ( you will get the same results in all routes )

req.protocol: http
req.hostname: localhost
req.get('Host'): localhost:5000
req.originalUrl: /a/b/c?d=true&e=true
req.query: { d: 'true', e: 'true' }

Not Fixed Properties ( will change in every route because it controlled by express itself )

Route: /

req.baseUrl: <blank>
req.url: /a/b/c?d=true&e=true
req.path: /a/b/c

Route /a

req.baseUrl: /a
req.url: /b/c?d=true&e=true
req.path: /b/c

Documentation: http://expressjs.com/en/api.html#req.baseUrl

URL Package Way

In the URL function, you will get the same results in every route so properties are always fixed.

Properties

enter image description here

const url = new URL(`${req.protocol}://${req.get('host')}${req.originalUrl}`);
console.log(url)

You will get the results like the below. I changed the order of the properties as per the image so it can match the image flow.

URL {
  href: 'http://localhost:5000/a/b/c?d=true&e=true',
  protocol: 'http:',
  username: '',
  password: '',
  hostname: 'localhost',
  port: '5000',
  host: 'localhost:5000',
  origin: 'http://localhost:5000',
  pathname: '/a/b/c',
  search: '?d=true&e=true',
  searchParams: URLSearchParams { 'd' => 'true', 'e' => 'true' },
  hash: ''
}

Note: Hash can not send to the server because it treats as Fragment in the server but you will get that in the client-side means browser.

Documentation: https://nodejs.org/api/url.html#url_new_url_input_base

Nisharg Shah
  • 16,638
  • 10
  • 62
  • 73
  • 1
    This answer is not correct in 2021. There is no obvious way to get the "port" part of the url. In the example it claims that ```req.get("host")``` will include the port but besides "host" being deprecated, this is just not the case. – Manuel Astudillo Dec 01 '21 at 03:21
  • 2
    `get()` is used for getting headers of the request and in the request, you have the `host` header so it simply calls the request header and gets the port and it's very safe to use and nothing is depereacted here – Nisharg Shah Dec 03 '21 at 06:08
41

I found it a bit of a PITA to get the requested url. I can't believe there's not an easier way in express. Should just be req.requested_url

But here's how I set it:

var port = req.app.settings.port || cfg.port;
res.locals.requested_url = req.protocol + '://' + req.host  + ( port == 80 || port == 443 ? '' : ':'+port ) + req.path;
binki
  • 7,754
  • 5
  • 64
  • 110
chovy
  • 72,281
  • 52
  • 227
  • 295
25

Here is a great way to add a function you can call on the req object to get the url

  app.use(function(req, res, next) {
    req.getUrl = function() {
      return req.protocol + "://" + req.get('host') + req.originalUrl;
    }
    return next();
  });

Now you have a function you can call on demand if you need it.

lostintranslation
  • 23,756
  • 50
  • 159
  • 262
  • 2
    This doesn't include the user:password that you can get in a full url 'http://user:pass@host.com:8080/p/a/t/h?query=string#hash' – Code Uniquely Nov 27 '14 at 10:15
  • @CodeUniquely true, but since that convention has been deprecated for over a decade now, hopefully no one is actually building userinfo specs into their APIs – Mike Jul 09 '16 at 22:30
  • That doesn't depricate. – Lodewijk Sep 22 '20 at 20:45
18

Using url.format:

var url = require('url');

This support all protocols and include port number. If you don't have a query string in your originalUrl you can use this cleaner solution:

var requrl = url.format({
    protocol: req.protocol,
    host: req.get('host'),
    pathname: req.originalUrl,
});

If you have a query string:

var urlobj = url.parse(req.originalUrl);
urlobj.protocol = req.protocol;
urlobj.host = req.get('host');
var requrl = url.format(urlobj);
mpolci
  • 2,999
  • 1
  • 23
  • 16
13

Use this,

var url = req.headers.host + '/' + req.url;
Vaghani Janak
  • 601
  • 5
  • 14
13

make req.host/req.hostname effective must have two condition when Express behind proxies:

  1. app.set('trust proxy', 'loopback'); in app.js
  2. X-Forwarded-Host header must specified by you own in webserver. eg. apache, nginx

nginx:

server {
    listen myhost:80;
    server_name  myhost;
    location / {
        root /path/to/myapp/public;
        proxy_set_header X-Forwarded-Host $host:$server_port;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://myapp:8080;
    }
}

apache:

<VirtualHost myhost:80>
    ServerName myhost
    DocumentRoot /path/to/myapp/public
    ProxyPass / http://myapp:8080/
    ProxyPassReverse / http://myapp:8080/
</VirtualHost>
zhi.yang
  • 425
  • 5
  • 10
  • the example from: https://www.nginx.com/resources/wiki/start/topics/examples/likeapache/ – zhi.yang Jun 15 '16 at 01:59
  • 2
    yep, nobody told that, if you have no correct configuration in apache or nginx, you will get `127.0.0.1` from `req.get('host')` – Spark.Bao Sep 07 '17 at 07:12
11

Just the code below was enough for me!

const baseUrl = `${request.protocol}://${request.headers.host}`;
// http://127.0.0.1:3333
Edy Segura
  • 517
  • 6
  • 10
11

You can get the full url from req of express.

function fetchPages(req, res, next) {

    let fullUrl = req.headers.host + req.originalUrl;
    console.log("full url ==> ",fullUrl);
}
buddemat
  • 4,552
  • 14
  • 29
  • 49
Milan Bhagat
  • 111
  • 1
  • 3
8

You need to construct it using req.headers.host + req.url. Of course if you are hosting in a different port and such you get the idea ;-)

g13n
  • 3,218
  • 2
  • 24
  • 19
8

I would suggest using originalUrl instead of URL:

var url = req.protocol + '://' + req.get('host') + req.originalUrl;

See the description of originalUrl here: http://expressjs.com/api.html#req.originalUrl

In our system, we do something like this, so originalUrl is important to us:

  foo = express();
  express().use('/foo', foo);
  foo.use(require('/foo/blah_controller'));

blah_controller looks like this:

  controller = express();
  module.exports = controller;
  controller.get('/bar/:barparam', function(req, res) { /* handler code */ });

So our URLs have the format:

www.example.com/foo/bar/:barparam

Hence, we need req.originalUrl in the bar controller get handler.

Amber Haq Dixon
  • 614
  • 7
  • 9
8
var full_address = req.protocol + "://" + req.headers.host + req.originalUrl;

or

var full_address = req.protocol + "://" + req.headers.host + req.baseUrl;
Reigel Gallarde
  • 64,198
  • 21
  • 121
  • 139
mlibre
  • 2,460
  • 3
  • 23
  • 32
7

You can combine req.protocol, req.hostname, and req.originalUrl. Note req.hostname rather than req.host or req.get("host") which works but is harder to read.

const completeUrl = `${req.protocol}://${req.hostname}${req.originalUrl}`;
Jacob
  • 1,577
  • 8
  • 24
6

My code looks like this,

params['host_url'] = req.protocol + '://' + req.headers.host + req.url;

Gaurav Gandhi
  • 3,041
  • 2
  • 27
  • 40
soomtong
  • 61
  • 1
  • 5
6

I use the node package 'url' (npm install url)

What it does is when you call

url.parse(req.url, true, true)

it will give you the possibility to retrieve all or parts of the url. More info here: https://github.com/defunctzombie/node-url

I used it in the following way to get whatever comes after the / in http://www.example.com/ to use as a variable and pull up a particular profile (kind of like facebook: http://www.facebook.com/username)

    var url = require('url');
    var urlParts = url.parse(req.url, true, true);
    var pathname = urlParts.pathname;
    var username = pathname.slice(1);

Though for this to work, you have to create your route this way in your server.js file:

self.routes['/:username'] = require('./routes/users');

And set your route file this way:

router.get('/:username', function(req, res) {
 //here comes the url parsing code
}
Sacha Nacar
  • 2,308
  • 20
  • 14
6

You can use this function in the route like this

app.get('/one/two', function (req, res) {
    const url = getFullUrl(req);
}

/**
 * Gets the self full URL from the request
 * 
 * @param {object} req Request
 * @returns {string} URL
 */
const getFullUrl = (req) => `${req.protocol}://${req.headers.host}${req.originalUrl}`;

req.protocol will give you http or https, req.headers.host will give you the full host name like www.google.com, req.originalUrl will give the rest pathName(in your case /one/two)

BigMan73
  • 1,344
  • 15
  • 14
Awais Ayub
  • 389
  • 3
  • 13
3

Thank you all for this information. This is incredibly annoying.

Add this to your code and you'll never have to think about it again:

var app = express();

app.all("*", function (req, res, next) {  // runs on ALL requests
    req.fullUrl = req.protocol + '://' + req.get('host') + req.originalUrl
        next()
})

You can do or set other things there as well, such as log to console.

Nico
  • 4,248
  • 1
  • 20
  • 19
1
async function (request, response, next) {
  const url = request.rawHeaders[9] + request.originalUrl;
  //or
  const url = request.headers.host + request.originalUrl;
}
trickso
  • 11
  • 2
  • Please don't post only code as an answer, but also provide an explanation of what your code does and how it solves the problem of the question. Answers with an explanation are usually more helpful and of better quality, and are more likely to attract upvotes – Ran Marciano Dec 28 '20 at 06:24
0

Usually I rely on these 2 in the code, depends on the server and proxy exists:

req.socket.remoteAddress

req.headers.referer

Xin
  • 33,823
  • 14
  • 84
  • 85
-3
const fullUrl = `${protocol}://${host}:${port}${url}`
      
    const responseString = `Full URL is: ${fullUrl}`;                       
    res.send(responseString);  
})
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103