Javascript는 일반적으로 정규 표현식을 사용하여 URL을 확인하여 형식이 올바른지 확인합니다. 예:
/^https?:///.test(url);
물론 RFC 3986, RFC 3966, 검증을 위한 RFC 4694, RFC 4759, RFC 4904 및 기타 표준 유효한 URL 라이브러리.
물론 형식에 따른 확인으로는 URL이 존재하는지 확인할 수 없으므로 url-valid를 사용하면 HTTP 요청을 기반으로 확인합니다.
인터페이스 디자인
사실 URL 주소를 전달하는 함수와 링크 사용 가능 여부를 반환하는 콜백만 있으면 됩니다.
그러나 요청은 알 수 없는 오류가 발생하기 쉽기 때문에 콜백 함수에 오류 매개변수를 전달합니다. 비어 있지 않으면 오류가 발생합니다.
또한 웹페이지의 관련 데이터를 얻고 이를 사용하여 향후 페이지에서 정보를 추출할 수도 있습니다.
최대한 체인운영합니다.
그래서 최종 사용법은 아마도 이렇습니다.
유효한(url)
.on('check', function (err, status) {
if (err) throw err;
status ?
console.log('url은 다음과 같습니다. available') :
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를 얻은 후 즉시 요청을 중단합니다.
301~303 처리
301~303은 리다이렉트 상태이기 때문에 해당 Location이 아직 존재하는지 계속해서 확인해야 한다.
process.nextTick을 사용하여 비동기적으로 실행
리스너 등록 후 코드를 실행하기 위해 process.nextTick을 사용하여 한 단계 작업을 수행합니다.
구현
/*!
* 유효
* MIT 라이선스
*/
module.exports = (function () {
'use strict';
var http = require('http')
, https = require('https')
, EventEmitter = require('events').EventEmitter
, URL = require('url')
, urlReg = /^(https?):///;
/**
* 유효
* @class
*/
function Valid(url, callback) {
var that = this;
this. url = url;
this.emitter = new EventEmitter();
process.nextTick(function () {
that.get(url);
});
this.fetch = false;
콜백 && this.emitter.on('check', callback);
}
Valid.prototype = {
생성자: Valid,
/**
* get
* @param {String} url
*/
get: 함수(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), 함수(err, valid) {
Emitter.emit('check', err, valid);
});
that.fetch && valid.on('data', function ( 오류, 데이터) {
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} 事件
* @param {Function} 回调
*/
on: 函数(事件,回调){
(event === 'data') && (this.fetch = true);
this.emitter.on(事件, 回调);
return this;
},
/**
* 摧毁
*/
destroy: function () {
this. emitter.removeAllListeners();
this.url = undefined;
this.emitter = null;
this.fetch = undefined;
},
/**
* 移除所有监听器
* @param
*/
removeAllListeners:函数(事件){
事件?
this.emitter.removeAllListeners(event) :
this.emitter.removeAllListeners();
返回此;
},
/**
* 听众
* @param
*/
监听器: 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;
}
}
}
/**
* 一个
* @param {String} url
* @param {Function} 回调
* @return {Valid}
*/
函数一(url, 回调) {
return (新的有效(网址,回调));
}
one.one = 1;
返回 1;
})();