【问题标题】:node.js check if a remote URL existsnode.js 检查远程 URL 是否存在
【发布时间】:2014-11-18 08:57:42
【问题描述】:

如何在不将其拉下的情况下检查 URL 是否存在?我使用以下代码,但它会下载整个文件。我只需要检查它是否存在。

app.get('/api/v1/urlCheck/', function (req,res) {
    var url=req.query['url'];
    var request = require('request');
    request.get(url, {timeout: 30000, json:false}, function (error, result) {
        res.send(result.body);

    });

});

感谢任何帮助!

【问题讨论】:

  • 您可以执行 HEAD 请求而不是 GET。无论您在那里使用什么模块,我想他们都会为它提供一个简单的界面。

标签: javascript node.js


【解决方案1】:

试试这个:

var http = require('http'),
    options = {method: 'HEAD', host: 'stackoverflow.com', port: 80, path: '/'},
    req = http.request(options, function(r) {
        console.log(JSON.stringify(r.headers));
    });
req.end();

【讨论】:

  • 自 2020 年 1 月起,请求包仅处于维护状态,不应再使用 (nodesource.com/blog/express-going-into-maintenance-mode)。最好选择替代品。 url-exists 基于请求,因此现在也已弃用。
  • @schlicki ,您将 npm 请求模块与 Node.JS 内部内置的 http 模块的请求功能混淆了
【解决方案2】:

谢谢!就是这样,封装在一个函数中(2017 年 5 月 30 日更新,外面有 require):

    var http = require('http'),
         url = require('url');

    exports.checkUrlExists = function (Url, callback) {
        var options = {
            method: 'HEAD',
            host: url.parse(Url).host,
            port: 80,
            path: url.parse(Url).pathname
        };
        var req = http.request(options, function (r) {
            callback( r.statusCode== 200);});
        req.end();
    }

它非常快(我大约需要 50 毫秒,但这取决于您的连接和服务器速度)。请注意,它也是非常基本的,即它不能很好地处理重定向......

【讨论】:

  • 你不应该在函数体内使用require,因为它是同步的。
  • 现有资源或 URL 可以返回不同于 200 的状态并且仍然有效
【解决方案3】:

2021 年更新

使用url-exist:

import urlExist from 'url-exist';

const exists = await urlExist('https://google.com');

// Handle result
console.log(exists);

2020 年更新

request 现在已被弃用,这导致url-exists 随之失效。请改用url-exist

const urlExist = require("url-exist");

(async () => {
    const exists = await urlExist("https://google.com");
    // Handle result
    console.log(exists)
})();

如果你(由于某种原因)需要同步使用,可以使用url-exist-sync

2019 年更新

自 2017 年以来,request 和回调样式函数(来自 url-exists)已不再使用。

但是,有一个修复方法。将url-exists 换成url-exist

所以不要使用:

const urlExists = require("url-exists")

urlExists("https://google.com", (_, exists) => {
    // Handle result
    console.log(exists)
})

使用这个:

const urlExist = require("url-exist");
 
(async () => {
    const exists = await urlExist("https://google.com");
    // Handle result
    console.log(exists)
})();

原始答案(2017 年)

如果你可以访问request 包,你可以试试这个:

const request = require("request")
const urlExists = url => new Promise((resolve, reject) => request.head(url).on("response", res => resolve(res.statusCode.toString()[0] === "2")))
urlExists("https://google.com").then(exists => console.log(exists)) // true

大部分逻辑已经由url-exists提供。

【讨论】:

  • 哈哈!!我急切地等待着 2021 年的版本。 @Richie 你太棒了!
  • 这是一个广泛的答案,但似乎 url-exists 不能很好地处理无效或自签名证书。我试过 process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;
  • 解决安全证书以访问网站的许多问题似乎都得到了解决。如果您在 Node.js 中遇到此问题,请尝试在 github.com/node-fetch/node-fetch 上打开问题
  • const urlExist = require("url-exist"); 更改为 let { default: urlExist } = await import("url-exist");import urlExist from "url-exist" 并将该行移到异步函数中。如果我们有const urlExist = require("url-exist");,它会给出“ERR_REQUIRE_ESM”错误。
  • 更新了答案
【解决方案4】:

只需使用url-exists npm 包来测试url是否存在

var urlExists = require('url-exists');

urlExists('https://www.google.com', function(err, exists) {
  console.log(exists); // true 
});

urlExists('https://www.fakeurl.notreal', function(err, exists) {
  console.log(exists); // false 
});

【讨论】:

  • 干净多了。感谢分享!
  • 是否可以选择与同步调用一起使用
  • @UlrichDohou 我不这么认为。因为要检查 url 是否存在,您必须向该 url 发出请求,而这又将是异步的。如果你只是想检查 url 在语义上是否正确,你可以使用 RegExp 来做同样的事情
  • @UlrichDohou:通过示例检查下面的答案以使其同步。 stackoverflow.com/a/49182165/384884
  • 这个包实际上包含 8 行代码。其他一切都是测试、包描述、许可证、自述文件和其他东西。
【解决方案5】:

require 进入函数在 Node.js 中是错误的方式。 遵循的 ES6 方法支持所有正确的 http 状态,当然如果您有像 fff.kkk 这样的坏“主机”,则可以检索错误

checkUrlExists(host,cb) {
    http.request({method:'HEAD',host,port:80,path: '/'}, (r) => {
        cb(null, r.statusCode >= 200 && r.statusCode < 400 );
    }).on('error', cb).end();
}

【讨论】:

  • 不确定,但这似乎是检查链接错误的最佳方法!!!
【解决方案6】:

看看 url-exists npm 包https://www.npmjs.com/package/url-exists

设置:

$ npm install url-exists

用途:

const urlExists = require('url-exists');

urlExists('https://www.google.com', function(err, exists) {
  console.log(exists); // true 
});

urlExists('https://www.fakeurl.notreal', function(err, exists) {
  console.log(exists); // false 
});

您还可以承诺它以利用 awaitasync

const util = require('util');
const urlExists = util.promisify(require('url-exists'));

let isExists = await urlExists('https://www.google.com'); // true
isExists = await urlExists('https://www.fakeurl.notreal'); // false

编码愉快!

【讨论】:

    【解决方案7】:

    使用其他响应作为参考,这是一个承诺版本,它也适用于 https uris(对于节点 6+):

    const http = require('http');
    const https = require('https');
    const url = require('url');
    
    const request = (opts = {}, cb) => {
      const requester = opts.protocol === 'https:' ? https : http;
      return requester.request(opts, cb);
    };
    
    module.exports = target => new Promise((resolve, reject) => {
      let uri;
    
      try {
        uri = url.parse(target);
      } catch (err) {
        reject(new Error(`Invalid url ${target}`));
      }
    
      const options = {
        method: 'HEAD',
        host: uri.host,
        protocol: uri.protocol,
        port: uri.port,
        path: uri.path,
        timeout: 5 * 1000,
      };
    
      const req = request(options, (res) => {
        const { statusCode } = res;
    
        if (statusCode >= 200 && statusCode < 300) {
          resolve(target);
        } else {
          reject(new Error(`Url ${target} not found.`));
        }
      });
    
      req.on('error', reject);
    
      req.end();
    });
    

    可以这样使用:

    const urlExists = require('./url-exists')
    
    urlExists('https://www.google.com')
      .then(() => {
        console.log('Google exists!');
      })
      .catch(() => {
        console.error('Invalid url :(');
      });
    

    【讨论】:

      【解决方案8】:

      我在您的代码中看到您已经在使用request 库,所以只需:

      const request = require('request');
      
      request.head('http://...', (error, res) => {
        const exists = !error && res.statusCode === 200;
      });
      

      【讨论】:

        【解决方案9】:

        如果你使用axios,你可以像这样获取头部:

        const checkUrl = async (url) => {
          try {
            await axios.head(fullUrl);
            return true;
          } catch (error) {
            if (error.response.status >= 400) {
              return false;
            }
          }
        }
        

        您可能希望根据您的要求自定义 status code 范围,例如401(未授权)仍然可能意味着 URL 存在但您无权访问。

        【讨论】:

          【解决方案10】:

          我的等待异步 ES6 解决方案,执行 HEAD 请求:

          // options for the http request
          let options = {
              host: 'google.de',
              //port: 80,  optional
              //path: '/'  optional
          }
          
          const http = require('http');
          
          // creating a promise (all promises a can be awaited)
          let isOk = await new Promise(resolve => {
              // trigger the request ('HEAD' or 'GET' - you should check if you get the expected result for a HEAD request first (curl))
              // then trigger the callback
              http.request({method:'HEAD', host:options.host, port:options.port, path: options.path}, result =>
                  resolve(result.statusCode >= 200 && result.statusCode < 400)
              ).on('error', resolve).end();
          });
          
          // check if the result was NOT ok
          if (!isOk) 
              console.error('could not get: ' + options.host);
          else
              console.info('url exists: ' + options.host);
          

          【讨论】:

            【解决方案11】:

            正如@schlicki 指出的那样,目前request 模块正在被弃用。他发布的link 中的替代方案之一是got

            const got = require('got');
            
            (async () => {
                try {
                    const response = await got('https://www.nodesource.com/');
                    console.log(response.body);
                    //=> '<!doctype html> ...'
                } catch (error) {
                    console.log(error.response.body);
                    //=> 'Internal server error ...'
                }
            })();
            

            但是使用这种方法,您将在reponse.body 中获得整个HTML 页面。此外,got 可能还有更多您可能不需要的功能。那就是我想在列表中添加另一个我找到的替代方案。当我使用portscanner 库时,我可以将它用于相同的目的,而无需下载网站的内容。如果网站使用https,您可能还需要使用 443 端口

            var portscanner = require('portscanner')
            
            // Checks the status of a single port
            portscanner.checkPortStatus(80, 'www.google.es', function(error, status) {
                // Status is 'open' if currently in use or 'closed' if available
                console.log(status)
            })
            

            无论如何,最接近的方法是@Richie Bendall 在他的帖子中解释的url-exist 模块。我只是想添加一些其他选择

            【讨论】:

              【解决方案12】:

              似乎很多人都推荐了一个库来使用,但是url-exist 包含一个数据获取库的依赖项,所以这里是使用所有本机节点模块的它的克隆:

              const http = require('http');
              const { parse, URL } = require('url');
              
              // https://github.com/sindresorhus/is-url-superb/blob/main/index.js
              function isUrl(str) {
                if (typeof str !== 'string') {
                  return false;
                }
              
                const trimmedStr = str.trim();
                if (trimmedStr.includes(' ')) {
                  return false;
                }
              
                try {
                  new URL(str); // eslint-disable-line no-new
                  return true;
                } catch {
                  return false;
                }
              }
              
              // https://github.com/Richienb/url-exist/blob/master/index.js
              function urlExists(url) {
                return new Promise((resolve) => {
                  if (!isUrl(url)) {
                    resolve(false);
                  }
              
                  const options = {
                    method: 'HEAD',
                    host: parse(url).host,
                    path: parse(url).pathname,
                    port: 80,
                  };
              
                  const req = http.request(options, (res) => {
                    resolve(res.statusCode < 400 || res.statusCode >= 500);
                  });
                  
                  req.end();
                });
              }
              
              urlExists(
                'https://stackoverflow.com/questions/26007187/node-js-check-if-a-remote-url-exists'
              ).then(console.log);
              

              这也可能会吸引那些不想出于非常简单的目的安装依赖项的人。

              【讨论】:

                【解决方案13】:

                这里有一些非常糟糕的答案。为这么小的一段代码使用第三方库是很愚蠢的。尝试做一些实际的编程! danwarfel 的回答让我有了一些了解,但它仍然不太正确:它泄漏内存,不遵循重定向,不支持 https(可能是你想要的)并且实际上并没有回答问题 - 它只是记录标题!这是我的版本:

                import * as https from "https";
                
                // Return true if the URL is found and returns 200. Returns false if there are
                // network errors or the status code is not 200. It will throw an exception
                // for configuration errors (e.g. malformed URLs).
                //
                // Note this only supports https, not http.
                //
                async function isUrlFound(url: string, maxRedirects = 20): Promise<boolean> {
                  const [statusCode, location] = await new Promise<[number?, string?]>(
                    (resolve, _reject) => {
                      const req = https.request(
                        url,
                        {
                          method: "HEAD",
                        },
                        response => {
                          // This is necessary to avoid memory leaks.
                          response.on("readable", () => response.read());
                          resolve([response.statusCode, response.headers["location"]]);
                        },
                      );
                      req.on("error", _err => resolve([undefined, undefined]));
                      req.end();
                    },
                  );
                
                  if (
                    statusCode !== undefined &&
                    statusCode >= 300 &&
                    statusCode < 400 &&
                    location !== undefined &&
                    maxRedirects > 0
                  ) {
                    return isUrlFound(location, maxRedirects - 1);
                  }
                  return statusCode === 200;
                }
                

                经过最低限度的测试,但似乎可以工作。

                【讨论】:

                  猜你喜欢
                  • 2010-11-24
                  • 1970-01-01
                  • 2012-05-16
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-05-09
                  • 1970-01-01
                  • 2015-07-26
                  • 1970-01-01
                  相关资源
                  最近更新 更多