NodeJS url验证(url-valid)的使用方法

  Javascript做url检验,通常是使用正则表达式来判定,其格式是否正确,例如:

  

复制代码 代码如下:

  /^https?:\/\//.test(url);

  当然还有更好的检测方法比如基于RFC 3986, RFC 3966, RFC 4694, RFC 4759, RFC 4904等标准的进行验证的valid-url库。

  不过个根据格式进行验证当然不能确定该url是否存在啦,所以就有了url-valid,我们基于HTTP请求进行验证。

  接口设计

  实际上我们只需要一个函数传入一个url地址,并回调返回该链接是否可用。

  但请求容易产生未知错误,所以我们在回调函数传入一个error参数,如果不为空,则有错误产生。

  我们可能还希望能够得到网页的相关数据,未来用在页面的信息提取上。

  尽可能链式操作吧。

  所以最后使用上大概是这样的:

  

复制代码 代码如下:

  valid(url)

  .on('check', function (err, status) {

  if (err) throw err;

  status ?

  console.log('url是可用的') :

  console.log('url是不可用的');

  })

  .on('data', function (err, data) {

  console.log(data);

  })

  .on('end', function (err, data) {

  console.log('请求结束');

  })

  HTTP GET 还是 HTTP HEAD

  本来我们想利用HTTP HEAD请求来实现的,因为HEAD请求只会返回头信息,这可以减少请求时间,但是HEAD请求,不一定所有链接都会支持。

  所以最后我们使用HTTP GET方式,在得到正确的statusCode后立刻abort掉请求。

  处理301-303

  因为301到303都是重定向状态所以,我们需要继续检查对应Location是否依然存在。

  利用process.nextTick异步执行

  为了在注册监听后,再执行代码,我们使用process.nextTick来一步操作。

  实现

  

复制代码 代码如下:

  /*!

  * valid

  * MIT Licensed

  */

  module.exports = (function () {

  'use strict';

  var http = require('http')

  , https = require('https')

  , EventEmitter = require('events').EventEmitter

  , URL = require('url')

  , urlReg = /^(https?):\/\//;

  /**

  * Valid

  * @class

  */

  function Valid(url, callback) {

  var that = this;

  this.url = url;

  this.emitter = new EventEmitter();

  process.nextTick(function () {

  that.get(url);

  });

  this.fetch = false;

  callback && this.emitter.on('check', callback);

  }

  Valid.prototype = {

  constructor: Valid,

  /**

  * get

  * @param {String} url

  */

  get: function (url) {

  var match = url.match(urlReg)

  , that = this;

  if (match) {

  var httpLib = (match[1].toLowerCase() === 'http') ? http : https

  , opts = URL.parse(url)

  , req;

  opts.agent = false;

  opts.method = 'GET';

  req = httpLib.request(opts, function (res) {

  var statusCode = res.statusCode;

  if (statusCode === 200) {

  that.emitter.emit('check', null, true);

  that.fetch ?

  (res.on('data', function (data) {

  that.emitter.emit('data', null, data);

  }) && res.on('end', function () {

  that.emitter.emit('end');

  })) :

  (req.abort() || that.emitter.emit('end'));

  } else if (300 < statusCode && statusCode < 304) {

  req.abort();

  var emitter = that.emitter

  , valid = one(URL.resolve(url, res.headers.location), function (err, valid) {

  emitter.emit('check', err, valid);

  });

  that.fetch && valid.on('data', function (err, data) {

  emitter.emit('data', err, data);

  });

  valid.on('error', function (err) {

  that.emitter.emit('error', err);

  });

  valid.on('end', function () {

  that.emitter.emit('end');

  });

  } else {

  that.emitter.emit('check', null, false);

  }

  res.on('error', function (err) {

  req.abort();

  that.emitter.emit('data', err);

  });

  });

  req.on('error', function (err) {

  req.abort();

  return that.emitter.emit('check', null, false);

  });

  req.end();

  } else {

  return that.emitter.emit('check', null, false);

  }

  },

  /**

  * on

  * @param {Stirng} event

  * @param {Function} callback

  */

  on: function (event, callback) {

  (event === 'data') && (this.fetch = true);

  this.emitter.on(event, callback);

  return this;

  },

  /**

  * destroy

  */

  destroy: function () {

  this.emitter.removeAllListeners();

  this.url = undefined;

  this.emitter = null;

  this.fetch = undefined;

  },

  /**

  * removeAllListeners

  * @param

  */

  removeAllListeners: function (event) {

  event ?

  this.emitter.removeAllListeners(event) :

  this.emitter.removeAllListeners();

  return this;

  },

  /**

  * listeners

  * @param

  */

  listeners: function (event) {

  if (event) {

  return this.emitter.listeners(event);

  } else {

  var res = []

  , that = this

  , _push = Array.prototype.push;

  Object.keys(this.emitter._events).forEach(function (key) {

  _push.apply(res, that.emitter.listeners(key));

  });

  return res;

  }

  }

  }

  /**

  * one

  * @param {String} url

  * @param {Function} callback

  * @return {Valid}

  */

  function one(url, callback) {

  return (new Valid(url, callback));

  }

  one.one = one;

  return one;

  })();