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


Posted in NodeJs onNovember 18, 2013

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;
})();
NodeJs 相关文章推荐
Ubuntu中搭建Nodejs开发环境过程分享
Jun 01 NodeJs
使用DNode实现php和nodejs之间通信的简单实例
Jul 06 NodeJs
nodejs利用http模块实现银行卡所属银行查询和骚扰电话验证示例
Dec 30 NodeJs
nodejs6下使用koa2框架实例
May 18 NodeJs
nodejs判断文件、文件夹是否存在及删除的方法
Nov 10 NodeJs
nodeJs实现基于连接池连接mysql的方法示例
Feb 10 NodeJs
基于nodejs的雪碧图制作工具的示例代码
Nov 05 NodeJs
NodeJs 文件系统操作模块fs使用方法详解
Nov 26 NodeJs
nodejs微信开发之授权登录+获取用户信息
Mar 17 NodeJs
nodejs分离html文件里面的js和css的方法
Apr 09 NodeJs
NodeJS 文件夹拷贝以及删除功能
Sep 03 NodeJs
Nodejs实现微信分账的示例代码
Jan 19 NodeJs
NodeJS与Mysql的交互示例代码
Aug 18 #NodeJs
利用NodeJS的子进程(child_process)调用系统命令的方法分享
Jun 05 #NodeJs
将nodejs打包工具整合到鼠标右键的方法
May 11 #NodeJs
用nodejs写的一个简单项目打包工具
May 11 #NodeJs
nodejs教程 安装express及配置app.js文件的详细步骤
May 11 #NodeJs
nodejs中exports与module.exports的区别详细介绍
Jan 14 #NodeJs
nodejs的require模块(文件模块/核心模块)及路径介绍
Jan 14 #NodeJs
You might like
基于PHP的登录和注册的功能的实现
2020/08/06 PHP
在b/s开发中经常用到的javaScript技术
2006/08/23 Javascript
使用jQuery简化Ajax开发 Ajax开发入门
2009/10/14 Javascript
jquery autocomplete自动完成插件的的使用方法
2010/08/07 Javascript
jQuery EasyUI 的EasyLoader功能介绍
2010/09/12 Javascript
JqueryMobile动态生成listView并实现刷新的两种方法
2014/03/05 Javascript
js定时器(执行一次、重复执行)
2014/03/07 Javascript
JavaScript中具名函数的多种调用方式总结
2014/11/08 Javascript
jQuery on方法传递参数示例
2014/12/09 Javascript
angularjs客户端实现压缩图片文件并上传实例
2015/07/06 Javascript
jQuery实现查找链接文字替换属性的方法
2016/06/27 Javascript
node.js实现博客小爬虫的实例代码
2016/10/08 Javascript
通过bootstrap全面学习less
2016/11/09 Javascript
Javascript基于jQuery UI实现选中区域拖拽效果
2016/11/25 Javascript
vue.js实现条件渲染的实例代码
2017/06/22 Javascript
JS按条件 serialize() 对应标签的使用方法
2017/07/24 Javascript
Vue异步加载about组件
2017/10/31 Javascript
vue项目中实现的微信分享功能示例
2019/01/21 Javascript
vue中的v-if和v-show的区别详解
2019/09/01 Javascript
加速vue组件渲染之性能优化
2020/04/09 Javascript
JavaScript 几种循环方式以及模块化的总结
2020/09/03 Javascript
举例简单讲解Python中的数据存储模块shelve的用法
2016/03/03 Python
Python实现GUI学生信息管理系统
2020/04/05 Python
python3+PyQt5实现文档打印功能
2018/04/24 Python
在Pandas中处理NaN值的方法
2019/06/25 Python
Pycharm及python安装详细步骤及PyCharm配置整理(推荐)
2020/07/31 Python
python 实现分组求和与分组累加求和代码
2020/05/18 Python
美国大城市最热门旅游景点门票:CityPASS
2016/12/16 全球购物
苹果音乐订阅:Apple Music
2018/08/02 全球购物
通信专业个人自我鉴定
2013/10/21 职场文书
电厂厂长岗位职责
2014/01/02 职场文书
2014年班级工作总结
2014/11/14 职场文书
关于艺术节的开幕致辞
2016/03/04 职场文书
2019年大学生职业生涯规划书
2019/03/25 职场文书
SpringBoot快速入门详解
2021/07/21 Java/Android
MySQL下载安装配置详细教程 附下载资源
2022/09/23 MySQL