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 相关文章推荐
nodejs教程 安装express及配置app.js文件的详细步骤
May 11 NodeJs
nodejs npm package.json中文文档
Sep 04 NodeJs
nodejs开发环境配置与使用
Nov 17 NodeJs
nodejs实现的一个简单聊天室功能分享
Dec 06 NodeJs
nodejs中操作mysql数据库示例
Dec 20 NodeJs
使用DNode实现php和nodejs之间通信的简单实例
Jul 06 NodeJs
深入nodejs中流(stream)的理解
Mar 27 NodeJs
详解Nodejs之静态资源处理
Jun 05 NodeJs
nodejs基础之常用工具模块util用法分析
Dec 26 NodeJs
Nodejs中的require函数的具体使用方法
Apr 02 NodeJs
独立部署小程序基于nodejs的服务器过程详解
Jun 24 NodeJs
nodejs和react实现即时通讯简易聊天室功能
Aug 21 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根据日期判断星座的函数分享
2014/02/13 PHP
php动态变量定义及使用
2015/06/10 PHP
PHP+redis实现的悲观锁机制示例
2018/06/12 PHP
理解JSON:3分钟课程
2011/10/28 Javascript
jquery.messager.js插件导致页面抖动的解决方法
2013/07/14 Javascript
js在IE与firefox的差异集锦
2014/11/11 Javascript
AngularJS模块学习之Anchor Scroll
2016/01/19 Javascript
javascript this详细介绍
2016/09/19 Javascript
jQuery中用on绑定事件时需注意的事项
2017/03/19 Javascript
jQuery插件开发发送短信倒计时功能代码
2017/05/09 jQuery
详解vue父子组件间传值(props)
2017/06/29 Javascript
基于JQuery的Ajax方法使用详解
2017/08/16 jQuery
React native ListView 增加顶部下拉刷新和底下点击刷新示例
2018/04/27 Javascript
微信小程序实现topBar底部选择栏效果
2018/07/20 Javascript
简述vue路由打开一个新的窗口的方法
2018/11/29 Javascript
vue动态禁用控件绑定disable的例子
2019/10/28 Javascript
微信小程序商品详情页底部弹出框
2019/11/22 Javascript
jquery添加div实现消息聊天框
2020/02/08 jQuery
[02:40]DOTA2超级联赛专访430 从小就爱玩对抗性游戏
2013/06/18 DOTA
Python模块学习 datetime介绍
2012/08/27 Python
python中get和post有什么区别
2020/06/19 Python
python利用opencv保存、播放视频
2020/11/02 Python
python list的index()和find()的实现
2020/11/16 Python
html5拖曳操作 HTML5实现网页元素的拖放操作
2013/01/02 HTML / CSS
秘书英文求职信范文
2014/01/31 职场文书
擅自离岗检讨书
2014/02/11 职场文书
分家协议书
2014/04/21 职场文书
企业年度评优方案
2014/06/02 职场文书
超市周年庆活动方案
2014/08/16 职场文书
2015年学校食堂工作总结
2015/04/22 职场文书
费用申请报告范文
2015/05/15 职场文书
2015年城乡环境综合治理工作总结
2015/07/24 职场文书
Python使用scapy模块发包收包
2021/05/07 Python
Mysql数据库值的添加、修改、删除及清空操作实例
2021/06/20 MySQL
7个关于Python的经典基础案例
2021/11/07 Python
SQLServer权限之只开启创建表权限
2022/04/12 SQL Server