【问题标题】:How to get the full URL in Express?如何在 Express 中获取完整的 URL?
【发布时间】:2012-04-28 07:46:32
【问题描述】:

假设我的示例网址是

http://example.com/one/two

我说我有以下路线

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

url 的值将是 /one/two

如何在 Express 中获取完整 URL? 例如,在上述情况下,我想收到http://example.com/one/two

【问题讨论】:

标签: node.js url express


【解决方案1】:
  1. 该协议以req.protocol 的形式提供。 docs here

    1. 在 express 3.0 之前,您可以假定协议为 http,除非您看到 req.get('X-Forwarded-Protocol') 已设置并具有值 https,在这种情况下您知道这是您的协议
  2. 如 Gopal 所示,主机来自 req.get('host')

  3. 希望您的 URL 中不需要非标准端口,但如果您确实需要知道它,您应该将它置于您的应用程序状态,因为它是您在服务器启动时传递给 app.listen 的任何内容时间。但是,在非标准端口上进行本地开发的情况下,Chrome 似乎将该端口包含在主机标头中,因此例如 req.get('host') 返回 localhost:3000。因此,至少对于标准端口上的生产站点并直接浏览到您的快速应用程序(没有反向代理)的情况,host 标头似乎对 URL 中的端口做了正确的事情。

  4. 路径来自req.originalUrl(感谢@pgrassant)。请注意,这确实包括查询字符串。 docs here on req.url and req.originalUrl。根据您打算对 URL 执行的操作,与 req.url 相比,originalUrl 可能是正确的值,也可能不是正确的值。

将所有这些组合在一起以重构绝对 URL。

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

【讨论】:

  • @dave 客户端可以发送它想要的任何标头(以及任何 URL、端口、随机非 HTTP 垃圾),但是,在某些时候,虚假或不准确的标头只会导致协议失败.例如,在虚拟主机环境中,不正确的“主机”标题将显示完全不同的网站。在 X-Forwarded-Protocol 的情况下,通常不是由实际客户端(浏览器)发送,而是由在您的应用程序前面提供 HTTPS 的反向代理(nginx/varnish/apache/whatever)发送。
  • 或者使用req.get('Host')而不是req.host,它给出了主机和端口部分。
  • 最好为此发布一个单独的问题。这个问题是关于快递的。
  • 请求头中的host参数可以被欺骗。如果以这种方式使用res.host,则可能存在“主机头攻击”。在 Django 框架中,他们有一个“允许的主机”变量,用于防止此类攻击。我使用一个配置变量,即我的root_url,可以将其添加到req.url 以完成。关于攻击:skeletonscribe.net/2013/05/…
  • 如果你想在不带参数的情况下添加req.originalUrl,只需执行req.originalUrl.split("?").shift()。来源:stackoverflow.com/a/32118818/2037431
【解决方案2】:

您可以使用the node.js API for URLs 并将来自express 的信息传递给URL.format(),而不是自己将这些东西连接在一起。

例子:

var url = require('url');

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

【讨论】:

  • 在我的情况下,req.get('host') 只返回 hostname 部分,而不是端口。不知道为什么,现在我从设置中收集端口号,并使用hostname 字段,而不是host
  • 我认为您的意思不是pathname,而是path。其中包括搜索/查询字符串
  • 这不适用于具有查询字符串的 URL。
  • 我发现这个 URL 对象很有用,所以如果你的 URL 中有一个查询字符串,你可以将它与 Peter Lyons 的答案结合起来进行设置,例如:const url = new URL(req.protocol + '://' + req.get('host') + req.originalUrl)
  • url.format 现已弃用。
【解决方案3】:

我发现获取请求的 url 有点像 PITA。我不敢相信没有更简单的表达方式。应该只是 req.requested_url

但我是这样设置的:

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

【讨论】:

  • 必须定义端口变量?
  • req.port 存在吗?它不在 Express 文档中?
  • 我的错。我假设您会知道您正在服务的端口并提前设置。我将再次更新示例。您也可以通过req.app.settings.port 获取
  • 当req.protocol为空时,是否表示http?
  • 这个不包括查询。它不完整。接受的答案更好。
【解决方案4】:

这是添加函数的好方法,您可以在 req 对象上调用以获取 url

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

现在你有了一个可以按需调用的函数。

【讨论】:

  • 这不包括用户:密码,您可以在完整的 url 'user:pass@host.com:8080/p/a/t/h?query=string#hash'中获得
  • @CodeUniquely true,但由于该约定已被弃用十多年,希望没有人真正将用户信息规范构建到他们的 API 中
  • 这并不贬义。
【解决方案5】:

使用url.format

var url = require('url');

这支持所有协议并包括端口号。如果您的 originalUrl 中没有查询字符串,您可以使用这个更简洁的解决方案:

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

如果你有一个查询字符串:

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

【讨论】:

    【解决方案6】:

    使req.host/req.hostname生效必须有两个条件Express behind proxies:

    1. app.set('trust proxy', 'loopback'); 在 app.js 中
    2. X-Forwarded-Host 标头必须由您在网络服务器中指定。例如。阿帕奇,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;
        }
    }
    

    阿帕奇

    <VirtualHost myhost:80>
        ServerName myhost
        DocumentRoot /path/to/myapp/public
        ProxyPass / http://myapp:8080/
        ProxyPassReverse / http://myapp:8080/
    </VirtualHost>
    

    【讨论】:

    【解决方案7】:

    使用这个,

    var url = req.headers.host + '/' + req.url;
    

    【讨论】:

    • 使用 var url = req.headers.host + req.url
    【解决方案8】:

    下面的代码对我来说就足够了!

    const baseUrl = `${request.protocol}://${request.headers.host}`;
    // http://127.0.0.1:3333
    

    【讨论】:

      【解决方案9】:

      2021 年

      以上答案工作正常,但文档不喜欢,因为url.parse 现在是legacy,所以如果你想对url 进行更多控制,我建议你使用new URL() 函数。

      高速公路

      您可以从下面的代码中获取Full URL

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

      示例网址:http://localhost:5000/a/b/c?d=true&e=true#f=false

      固定属性(您将在所有路线中获得相同的结果)

      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(每条路线都会发生变化,因为它由 express 自己控制)

      路线:/

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

      路由/a

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

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

      网址打包方式

      URL 函数中,您将在每条路由中获得相同的结果,因此属性始终是固定的

      属性

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

      您将获得如下结果。我根据图像更改了属性的顺序,以便它可以匹配图像流。

      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: ''
      }
      

      注意Hash 无法发送到服务器,因为它在服务器中被视为Fragment,但您会在客户端即浏览器中得到它。

      文档:https://nodejs.org/api/url.html#url_new_url_input_base

      【讨论】:

      • 这个答案在 2021 年不正确。没有明显的方法可以获取 url 的“端口”部分。在示例中,它声称req.get("host") 将包含端口,但除了不推荐使用“主机”之外,情况并非如此。
      • get() 用于获取请求的标头,在请求中,您有 host 标头,因此它只需调用请求标头并获取端口,使用起来非常安全,什么都没有此处已废弃
      【解决方案10】:

      我建议使用 originalUrl 而不是 URL:

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

      在此处查看 originalUrl 的说明: http://expressjs.com/api.html#req.originalUrl

      在我们的系统中,我们做了这样的事情,所以 originalUrl 对我们很重要:

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

      blah_controller 看起来像这样:

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

      所以我们的 URL 具有以下格式:

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

      因此,我们需要在 bar 控制器获取处理程序中使用 req.originalUrl。

      【讨论】:

        【解决方案11】:
        var full_address = req.protocol + "://" + req.headers.host + req.originalUrl;
        

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

        【讨论】:

          【解决方案12】:

          您需要使用req.headers.host + req.url 构建它。当然,如果您在不同的端口托管,那么您就会明白;-)

          【讨论】:

          • 除了协议之外,我什么都知道了……有什么可以告诉我的吗?
          • 获取协议使用:req.protocol
          【解决方案13】:

          我的代码是这样的,

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

          【讨论】:

            【解决方案14】:

            你可以像这样在路由中使用这个函数

            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 会给你 http 或 https, req.headers.host 会给你完整的主机名,比如 www.google.com, req.originalUrl 将提供其余的 pathName(在您的情况下为 /one/two

            【讨论】:

              【解决方案15】:

              我使用节点包'url'(npm install url)

              它的作用是当你调用时

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

              它将使您可以检索全部或部分 url。更多信息在这里:https://github.com/defunctzombie/node-url

              我以以下方式使用它来获取 http://www.example.com/ 中 / 之后的任何内容以用作变量并提取特定配置文件(有点像 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);
              

              尽管要让它工作,你必须在你的 server.js 文件中以这种方式创建你的路由:

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

              并以这种方式设置您的路线文件:

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

              【讨论】:

                【解决方案16】:

                感谢大家提供这些信息。这是令人难以置信的烦人。

                将此添加到您的代码中,您将永远不必再考虑它:

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

                您也可以在此处执行或设置其他操作,例如登录到控制台。

                【讨论】:

                  【解决方案17】:
                  async function (request, response, next) {
                    const url = request.rawHeaders[9] + request.originalUrl;
                    //or
                    const url = request.headers.host + request.originalUrl;
                  }
                  

                  【讨论】:

                  • 请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助、质量更好,并且更有可能吸引投票
                  【解决方案18】:

                  您可以组合req.protocolreq.hostnamereq.originalUrl。请注意 req.hostname 而不是 req.hostreq.get("host"),它们有效但更难阅读。

                  const completeUrl = `${req.protocol}://${req.hostname}${req.originalUrl}`;
                  

                  【讨论】:

                    【解决方案19】:

                    只需将其放在.env 中,其中 .env 文件会被 .gitignore 忽略,因此对于每个服务器环境,您将拥有不同的 .env,其中包含该服务器的主机字符串

                    .env 代码

                    HOSTNAME=example.com
                    

                    你想要hotname的文件。

                    const dotenv = require("dotenv");
                    dotenv.config();
                    
                    console.log('hostname: '+process.env.HOSTNAME)
                    

                    输出:

                    hostname: example.com
                    

                    【讨论】:

                      【解决方案20】:

                      你可以从 express 的 req 中获取完整的 url。

                      function fetchPages(req, res, next) {
                      
                          let fullUrl = req.headers.host + req.originalUrl;
                          console.log("full url ==> ",fullUrl);
                      }
                      

                      【讨论】:

                        【解决方案21】:

                        通常我依赖这2个,取决于服务器和代理是否存在:

                        req.socket.remoteAddress

                        req.headers.referer

                        【讨论】:

                          【解决方案22】:
                          const fullUrl = `${protocol}://${host}:${port}${url}`
                                
                              const responseString = `Full URL is: ${fullUrl}`;                       
                              res.send(responseString);  
                          })
                          

                          【讨论】:

                            猜你喜欢
                            • 2019-04-08
                            • 2015-03-11
                            • 2016-07-05
                            • 1970-01-01
                            • 2013-06-08
                            • 2017-06-06
                            • 2015-10-28
                            • 2012-02-07
                            相关资源
                            最近更新 更多