• NodeJS的url验证库模块url-valid


    这是我10月份做的项目其中的一个部件,主要用于url检验的。

    我们知道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来一步操作。

    实现

    OK,大致就这样,下面就是实现:

    /*!
     * valid
     * Copyright (c) 2013 Daniel Yang <miniflycn@justany.net>
     * 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;
    })();

    源码地址

     https://github.com/miniflycn/url-valid

  • 相关阅读:
    JS字符串截取(获取指定字符后面的所有字符内容)
    vue图片上传插件
    php获取两个日期之间的所有日期
    laravel做定时任务时,加参数(也可缓存参数)
    前端传参数(数组,值为json字符串),后端接收json_decode()转为数组,数组为空值
    springboot的maven多模块项目
    如何给文件重命名
    springboot的get请求和post请求
    java调用ffmpeg
    mybatis批量插入List
  • 原文地址:https://www.cnblogs.com/justany/p/3427375.html
Copyright © 2020-2023  润新知