¿Cómo obtener la url completa en Express?


487

Digamos que mi URL de muestra es

http://example.com/one/two

y digo que tengo la siguiente ruta

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

El valor de urlserá /one/two.

¿Cómo obtengo la URL completa en Express? Por ejemplo, en el caso anterior, me gustaría recibir http://example.com/one/two.


66
Para su información, puede inspeccionar el objeto de solicitud y mirar, pero soy un hipócrita y lo encontré aquí.
Jason Sebring

Respuestas:


742
  1. El protocolo está disponible como req.protocol. documentos aquí

    1. Antes de express 3.0, el protocolo que puede suponer ser a httpmenos que vea que req.get('X-Forwarded-Protocol')está configurado y tiene el valor https, en cuyo caso sabe que ese es su protocolo
  2. El host proviene de lo req.get('host')que Gopal ha indicado

  3. Espero que no necesite un puerto no estándar en sus URL, pero si necesita saberlo, lo tendrá en el estado de su aplicación porque es lo que haya pasado al app.listenmomento del inicio del servidor. Sin embargo, en el caso del desarrollo local en un puerto no estándar, Chrome parece incluir el puerto en el encabezado del host , por lo que req.get('host')devuelve localhost:3000, por ejemplo. Entonces, al menos para los casos de un sitio de producción en un puerto estándar y navegando directamente a su aplicación express (sin proxy inverso), el hostencabezado parece hacer lo correcto con respecto al puerto en la URL.

  4. El camino viene de req.originalUrl(gracias @pgrassant). Tenga en cuenta que esto INCLUYE la cadena de consulta. documentos aquí en req.url y req.originalUrl . Dependiendo de lo que pretenda hacer con la URL, originalUrlpuede o no ser el valor correcto en comparación con req.url.

Combina todos esos elementos para reconstruir la URL absoluta.

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

3
@dave un cliente puede enviar cualquier encabezado que desee (así como cualquier URL, puerto, basura aleatoria que no sea HTTP), sin embargo, en algún momento los encabezados falsos o inexactos simplemente harán que el protocolo falle. Por ejemplo, en un entorno de host virtual, un encabezado "host" incorrecto mostrará un sitio web completamente diferente. En el caso del Protocolo X-Reenviado, eso generalmente no lo envía el cliente real (navegador) sino el proxy inverso (nginx / varnish / apache / lo que sea) que está sirviendo HTTPS frente a su aplicación.
Peter Lyons

59
O use en req.get('Host')lugar de lo req.hostque le da al host más la sección del puerto.
diosney

1
Probablemente sea mejor publicar una pregunta separada para eso. Esta pregunta es sobre express.
Peter Lyons

18
El hostparámetro en los encabezados de solicitud se puede suplantar. Hay un posible "ataque de encabezado de host" si se usa de res.hostesta manera. En el marco de Django, tienen una variable de "hosts permitidos" que se utiliza para prevenir dicho ataque. Yo uso una variable de configuración que es mi root_urlque se puede agregar a la req.urlfinalización. Sobre el ataque: skeletonscribe.net/2013/05/…
Amir Eldor

1
Si desea agregar req.originalUrlsin parámetros, simplemente hágalo req.originalUrl.split("?").shift(). Fuente: stackoverflow.com/a/32118818/2037431
Marcos Pereira

131

En lugar de concatenar las cosas por su cuenta, podría usar la API de node.js para URL y pasar URL.format()la información de express.

Ejemplo:

var url = require('url');

function fullUrl(req) {
  return url.format({
    protocol: req.protocol,
    host: req.get('host'),
    pathname: req.originalUrl
  });
}

44
En mi caso, req.get('host')solo devuelve la parte del nombre de host , no el puerto. No sé por qué, pero ahora obtengo el número de puerto de la configuración y uso el hostnamecampo en lugar de host.
maxkoryukov

1
En lugar de pathname, creo que te refieres path. Que incluye búsqueda / cadena de consulta
Félix Sanz

3
Esto no funciona para las URL que tienen una cadena de consulta.
Keith

37

Me pareció un poco PITA obtener la URL solicitada. No puedo creer que no haya una manera más fácil de expresar. Debería ser solo req.requested_url

Pero así es como lo configuro:

var port = req.app.settings.port || cfg.port;
res.locals.requested_url = req.protocol + '://' + req.host  + ( port == 80 || port == 443 ? '' : ':'+port ) + req.path;

puerto variable tiene que ser definido?
Amol M Kulkarni

44
¿Existe req.port? ¿No está en la documentación Express?
Mitar

Culpa mía. Supuse que sabrías de qué puerto estás sirviendo y configuré eso antes. Actualizaré el ejemplo nuevamente. También puedes conseguirloreq.app.settings.port
chovy

cuando req.protocol está vacío, ¿significa http?
Codebeat

Este no incluye la consulta. No esta completo. La respuesta aceptada es mejor.
Kostanos

17

Usando url.format :

var url = require('url');

Esto admite todos los protocolos e incluye el número de puerto. Si no tiene una cadena de consulta en su URL original, puede usar esta solución más limpia:

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

Si tiene una cadena de consulta:

var urlobj = url.parse(req.originalUrl);
urlobj.protocol = req.protocol;
urlobj.host = req.get('host');
var requrl = url.format(urlobj);

16

Aquí hay una excelente manera de agregar una función que puede invocar en el objeto req para obtener la URL

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

Ahora tiene una función a la que puede llamar bajo demanda si la necesita.


2
Esto no incluye el usuario: contraseña que puede obtener en una url completa ' usuario: pass@host.com: 8080 / p / a / t / h? Query = string # hash '
Código exclusivo

@CodeUniquely cierto, pero dado que esa convención ha quedado en desuso durante más de una década, con suerte nadie está realmente incorporando especificaciones de información de usuario en sus API
Mike

11

hacer que req.host/req.hostname sea efectivo debe tener dos condiciones cuando Express detrás de proxies :

  1. app.set('trust proxy', 'loopback'); en app.js
  2. X-Forwarded-HostEl encabezado debe ser especificado por usted en el servidor web. p.ej. 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>


1
sí, nadie dijo eso, si no tienes la configuración correcta en apache o nginx, obtendrás 127.0.0.1dereq.get('host')
Spark.Bao


7
var full_address = req.protocol + "://" + req.headers.host + req.originalUrl;

o

var full_address = req.protocol + "://" + req.headers.host + req.baseUrl;

6

Necesitas construirlo usando req.headers.host + req.url. Por supuesto, si está alojado en un puerto diferente y de este modo se le ocurre la idea ;-)


1
Eso me da todo menos el protocolo ... ¿hay algo que pueda decirme eso?
Chris Abrams

Para obtener el uso del protocolo:req.protocol
mrded

6

Sugeriría usar originalUrl en lugar de URL:

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

Vea la descripción de originalUrl aquí: http://expressjs.com/api.html#req.originalUrl

En nuestro sistema, hacemos algo como esto, por lo que originalUrl es importante para nosotros:

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

blah_controller se ve así:

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

Entonces nuestras URL tienen el formato:

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

Por lo tanto, necesitamos req.originalUrl en el controlador de barra get get.


6

Mi código se ve así,

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


5

Yo uso el paquete de nodos 'url' (npm install url)

Lo que hace es cuando llamas

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

le dará la posibilidad de recuperar todas o partes de la url. Más información aquí: https://github.com/defunctzombie/node-url

Lo utilicé de la siguiente manera para obtener lo que viene después de / en http://www.example.com/ para usarlo como una variable y extraer un perfil en particular (algo así como 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);

Aunque para que esto funcione, debe crear su ruta de esta manera en su archivo server.js:

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

Y configure su archivo de ruta de esta manera:

router.get('/:username', function(req, res) {
 //here comes the url parsing code
}

3

Puedes usar esta función en la ruta como esta

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.protocolle dará http o https, req.headers.hostle dará el nombre completo del host como www.google.com, req.originalUrlle dará el resto pathName(en su caso /one/two)


¿Podría explicar cómo funciona esta solución? Evite publicar solo respuestas de código en Stack Overflow.
Arcath

@Arcath elaborado.
Awais Ayub

1

Gracias a todos por esta información. Esto es increíblemente molesto.

Agregue esto a su código y nunca tendrá que pensarlo nuevamente:

var app = express();

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

También puede hacer o configurar otras cosas allí, como iniciar sesión en la consola.


1

¡Solo el código a continuación fue suficiente para mí!

const baseUrl = `${request.protocol}://${request.headers.host}`;
// http://127.0.0.1:3333
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.