检查JavaScript字符串是否是URL

在JavaScript中是否有一种方法来检查字符串是否是URL?

regex被排除在外,因为URL很可能写成stackoverflow;也就是说,它可能没有.comwwwhttp

646107 次浏览

有答案的相关问题

或者来自Devshed的Regexp:

function validURL(str) {
var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name
'((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
'(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
'(\\#[-a-z\\d_]*)?$','i'); // fragment locator
return !!pattern.test(str);
}
function isURL(str) {
var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.?)+[a-z]{2,}|'+ // domain name
'((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
'(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
'(\\#[-a-z\\d_]*)?$','i'); // fragment locator
return pattern.test(str);
}

我不能评论最接近# 5717133的帖子,但下面是我想出如何让@tom-gullen regex工作的方法。

/^(https?:\/\/)?((([a-z\d]([a-z\d-]*[a-z\d])*)\.)+[a-z]{2,}|((\d{1,3}\.){3}\d{1,3}))(\:\d+)?(\/[-a-z\d%_.~+]*)*(\?[;&a-z\d%_.~+=-]*)?(\#[-a-z\d_]*)?$/i

使用javascript验证Url如下所示

function ValidURL(str) {
var regex = /(?:https?):\/\/(\w+:?\w*)?(\S+)(:\d+)?(\/|\/([\w#!:.?+=&%!\-\/]))?/;
if(!regex .test(str)) {
alert("Please enter valid URL.");
return false;
} else {
return true;
}
}

我建议使用锚元素,而不是使用正则表达式。

当你设置anchorhref属性时,会设置其他各种属性。

var parser = document.createElement('a');
parser.href = "http://example.com:3000/pathname/?search=test#hash";


parser.protocol; // => "http:"
parser.hostname; // => "example.com"
parser.port;     // => "3000"
parser.pathname; // => "/pathname/"
parser.search;   // => "?search=test"
parser.hash;     // => "#hash"
parser.host;     // => "example.com:3000"

< a href = " https://gist.github.com/jlong/2428561 " > < / >来源

然而,如果href绑定的值不是一个有效的url,那么这些辅助属性的值将是空字符串。

编辑:正如注释中指出的:如果使用了无效url,则可以替换当前url的属性。

所以,只要你没有传递当前页面的URL,你可以这样做:

function isValidURL(str) {
var a  = document.createElement('a');
a.href = str;
return (a.host && a.host != window.location.host);
}

依赖库: https://www.npmjs.com/package/valid-url < / p >

import { isWebUri } from 'valid-url';
// ...
if (!isWebUri(url)) {
return "Not a valid url.";
}

如果你想检查字符串是否是有效的HTTP URL,你可以使用URL构造函数(它会抛出一个畸形的字符串):

function isValidHttpUrl(string) {
let url;
try {
url = new URL(string);
} catch (_) {
return false;
}
return url.protocol === "http:" || url.protocol === "https:";
}
console.log("http://example.com: "+isValidHttpUrl("https://example.com"));
console.log("example.com: "+isValidHttpUrl("example.com"));

注意:对于RFC 3886, URL必须以一个方案开头(不限于http/https),例如:

  • www.example.com不是有效的URL(缺少方案)
  • javascript:void(0)是有效的URL,尽管不是HTTP URL
  • http://..是有效的URL,主机为..(它是否解析取决于你的DNS)
  • https://example..com是有效的URL,与上面相同

(我没有代表评论ValidURL的例子;因此,把这个作为一个答案。)

虽然不鼓励使用协议相对url (协议相对URL),但有时确实会使用它们。要用正则表达式验证这样的URL,协议部分可以是可选的,例如:

function isValidURL(str) {
var pattern = new RegExp('^((https?:)?\\/\\/)?'+ // protocol
'(?:\\S+(?::\\S*)?@)?' + // authentication
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name
'((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
'(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
'(\\#[-a-z\\d_]*)?$','i'); // fragment locater
if (!pattern.test(str)) {
return false;
} else {
return true;
}
}

正如其他人指出的那样,正则表达式似乎不是验证url的最佳方法。

对已接受答案的改进…

  • 检查ftp/ftps作为协议
  • 对反斜杠有双重转义(\\)
  • 确保域名有一个点和一个扩展名(.com .io .xyz)
  • 允许在路径中使用冒号(:),例如http://thingiverse.com/download:1894343
  • 允许在路径中使用& (&),例如http://en.wikipedia.org/wiki/Procter_&_Gamble
  • 允许在路径中使用@符号,例如https://medium.com/@techytimo

    isURL(str) {
    var pattern = new RegExp('^((ft|htt)ps?:\\/\\/)?'+ // protocol
    '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name and extension
    '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address
    '(\\:\\d+)?'+ // port
    '(\\/[-a-z\\d%@_.~+&:]*)*'+ // path
    '(\\?[;&a-z\\d%@_.,~+&:=-]*)?'+ // query string
    '(\\#[-a-z\\d_]*)?$','i'); // fragment locator
    return pattern.test(str);
    }
    

我一直用来验证URL“字符串”的一个函数是:

var matcher = /^(?:\w+:)?\/\/([^\s\.]+\.\S{2}|localhost[\:?\d]*)\S*$/;


function isUrl(string){
return matcher.test(string);
}

这个函数将返回一个布尔值,不管字符串是否是URL。

例子:

isUrl("https://google.com");     // true
isUrl("http://google.com");      // true
isUrl("http://google.de");       // true
isUrl("//google.de");            // true
isUrl("google.de");              // false
isUrl("http://google.com");      // true
isUrl("http://localhost");       // true
isUrl("https://sdfasd");         // false

正如已经指出的,完美的正则表达式是难以捉摸的,但似乎仍然是一个合理的方法(替代方案是服务器端测试或新的实验URL API)。然而,对于常见的url,高排名的答案通常会返回false,更糟糕的是,即使是isURL('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')这样简单的字符串,也会冻结你的应用/页面几分钟。在一些评论中已经指出了这一点,但大多数人可能没有输入错误的值来查看它。这样的挂起使得代码在任何严肃的应用程序中都无法使用。我认为这是由于在((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.?)+[a-z]{2,}|' ...这样的代码中重复的不区分大小写的集合。去掉“i”,它就挂不起来了,当然也不会像预期的那样工作。但是即使使用忽略大小写标志,这些测试也会拒绝允许的高unicode值。

已经提到的最好的是:

function isURL(str) {
return /^(?:\w+:)?\/\/([^\s\.]+\.\S{2}|localhost[\:?\d]*)\S*$/.test(str);
}

这来自Github segmentio / is-url。代码存储库的好处是,您可以看到测试和任何问题,以及测试字符串。有一个分支将允许字符串缺少协议,如google.com,尽管你可能做了太多的假设。存储库已经更新,我不打算在这里保持镜像。它被分解成单独的测试,以避免RegEx redos,这可以用于DOS攻击(我认为您不必担心客户端js,但您确实需要担心您的页面挂起太长时间,以至于您的访问者离开您的网站)。

我还见过另一个库甚至可以更好的isURL在dperini/regex- webl .js,但它非常复杂。它有一个更大的有效和无效url的测试列表。上面的简单方法仍然通过了所有的正数,只阻止了一些奇怪的负数,如http://a.b--c.de/和特殊的ip。

无论你选择哪一个,在使用浏览器的开发人员工具检查器时,通过这个函数运行它,这个函数是我从dperini/regex- webburl .js上的测试中改编的。

function testIsURL() {
//should match
console.assert(isURL("http://foo.com/blah_blah"));
console.assert(isURL("http://foo.com/blah_blah/"));
console.assert(isURL("http://foo.com/blah_blah_(wikipedia)"));
console.assert(isURL("http://foo.com/blah_blah_(wikipedia)_(again)"));
console.assert(isURL("http://www.example.com/wpstyle/?p=364"));
console.assert(isURL("https://www.example.com/foo/?bar=baz&inga=42&quux"));
console.assert(isURL("http://✪df.ws/123"));
console.assert(isURL("http://userid:password@example.com:8080"));
console.assert(isURL("http://userid:password@example.com:8080/"));
console.assert(isURL("http://userid@example.com"));
console.assert(isURL("http://userid@example.com/"));
console.assert(isURL("http://userid@example.com:8080"));
console.assert(isURL("http://userid@example.com:8080/"));
console.assert(isURL("http://userid:password@example.com"));
console.assert(isURL("http://userid:password@example.com/"));
console.assert(isURL("http://142.42.1.1/"));
console.assert(isURL("http://142.42.1.1:8080/"));
console.assert(isURL("http://➡.ws/䨹"));
console.assert(isURL("http://⌘.ws"));
console.assert(isURL("http://⌘.ws/"));
console.assert(isURL("http://foo.com/blah_(wikipedia)#cite-1"));
console.assert(isURL("http://foo.com/blah_(wikipedia)_blah#cite-1"));
console.assert(isURL("http://foo.com/unicode_(✪)_in_parens"));
console.assert(isURL("http://foo.com/(something)?after=parens"));
console.assert(isURL("http://☺.damowmow.com/"));
console.assert(isURL("http://code.google.com/events/#&product=browser"));
console.assert(isURL("http://j.mp"));
console.assert(isURL("ftp://foo.bar/baz"));
console.assert(isURL("http://foo.bar/?q=Test%20URL-encoded%20stuff"));
console.assert(isURL("http://مثال.إختبار"));
console.assert(isURL("http://例子.测试"));
console.assert(isURL("http://उदाहरण.परीक्षा"));
console.assert(isURL("http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com"));
console.assert(isURL("http://1337.net"));
console.assert(isURL("http://a.b-c.de"));
console.assert(isURL("http://223.255.255.254"));
console.assert(isURL("postgres://u:p@example.com:5702/db"));
console.assert(isURL("https://d1f4470da51b49289906b3d6cbd65074@app.getsentry.com/13176"));


//SHOULD NOT MATCH:
console.assert(!isURL("http://"));
console.assert(!isURL("http://."));
console.assert(!isURL("http://.."));
console.assert(!isURL("http://../"));
console.assert(!isURL("http://?"));
console.assert(!isURL("http://??"));
console.assert(!isURL("http://??/"));
console.assert(!isURL("http://#"));
console.assert(!isURL("http://##"));
console.assert(!isURL("http://##/"));
console.assert(!isURL("http://foo.bar?q=Spaces should be encoded"));
console.assert(!isURL("//"));
console.assert(!isURL("//a"));
console.assert(!isURL("///a"));
console.assert(!isURL("///"));
console.assert(!isURL("http:///a"));
console.assert(!isURL("foo.com"));
console.assert(!isURL("rdar://1234"));
console.assert(!isURL("h://test"));
console.assert(!isURL("http:// shouldfail.com"));
console.assert(!isURL(":// should fail"));
console.assert(!isURL("http://foo.bar/foo(bar)baz quux"));
console.assert(!isURL("ftps://foo.bar/"));
console.assert(!isURL("http://-error-.invalid/"));
console.assert(!isURL("http://a.b--c.de/"));
console.assert(!isURL("http://-a.b.co"));
console.assert(!isURL("http://a.b-.co"));
console.assert(!isURL("http://0.0.0.0"));
console.assert(!isURL("http://10.1.1.0"));
console.assert(!isURL("http://10.1.1.255"));
console.assert(!isURL("http://224.1.1.1"));
console.assert(!isURL("http://1.1.1.1.1"));
console.assert(!isURL("http://123.123.123"));
console.assert(!isURL("http://3628126748"));
console.assert(!isURL("http://.www.foo.bar/"));
console.assert(!isURL("http://www.foo.bar./"));
console.assert(!isURL("http://.www.foo.bar./"));
console.assert(!isURL("http://10.1.1.1"));}

然后测试这串a。

在你发布一个看起来很棒的正则表达式之前,请参阅Mathias Bynens的isURL正则表达式的比较以获取更多信息。

你可以使用URL原生API:

  const isUrl = string => {
try { return Boolean(new URL(string)); }
catch(e){ return false; }
}

我使用下面的函数来验证URL是否有http/https:

function isValidURL(string) {
var res = string.match(/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g);
return (res !== null)
};


var testCase1 = "http://en.wikipedia.org/wiki/Procter_&_Gamble";
console.log(isValidURL(testCase1)); // return true


var testCase2 = "http://www.google.com/url?sa=i&rct=j&q=&esrc=s&source=images&cd=&docid=nIv5rk2GyP3hXM&tbnid=isiOkMe3nCtexM:&ved=0CAUQjRw&url=http%3A%2F%2Fanimalcrossing.wikia.com%2Fwiki%2FLion&ei=ygZXU_2fGKbMsQTf4YLgAQ&bvm=bv.65177938,d.aWc&psig=AFQjCNEpBfKnal9kU7Zu4n7RnEt2nerN4g&ust=1398298682009707";
console.log(isValidURL(testCase2)); // return true


var testCase3 = "https://sdfasd";
console.log(isValidURL(testCase3)); // return false


var testCase4 = "dfdsfdsfdfdsfsdfs";
console.log(isValidURL(testCase4)); // return false


var testCase5 = "magnet:?xt=urn:btih:123";
console.log(isValidURL(testCase5)); // return false


var testCase6 = "https://stackoverflow.com/";
console.log(isValidURL(testCase6)); // return true


var testCase7 = "https://w";
console.log(isValidURL(testCase7)); // return false


var testCase8 = "https://sdfasdp.ppppppppppp";
console.log(isValidURL(testCase8)); // return false

我认为使用本机URL API比@pavlo建议的复杂正则表达式模式更好。虽然它有一些缺点,但我们可以通过一些额外的代码来修复。对于以下有效url,此方法失败。

//cdn.google.com/script.js

我们可以预先添加缺失的协议来避免这种情况。它也无法检测以下无效的url。

http://w
http://..

那么为什么要检查整个url呢?我们可以检查定义域。我从在这里借用了正则表达式来验证域。

function isValidUrl(string) {
if (string && string.length > 1 && string.slice(0, 2) == '//') {
string = 'http:' + string; //dummy protocol so that URL works
}
try {
var url = new URL(string);
return url.hostname && url.hostname.match(/^([a-z0-9])(([a-z0-9-]{1,61})?[a-z0-9]{1})?(\.[a-z0-9](([a-z0-9-]{1,61})?[a-z0-9]{1})?)?(\.[a-zA-Z]{2,4})+$/) ? true : false;
} catch (_) {
return false;
}
}

hostname属性是javascript:void(0)的空字符串,所以它也适用于此,你也可以添加IP地址验证器。我最喜欢坚持使用本地API,并希望它在不久的将来开始支持一切。

这里还有另一种方法。

// ***note***: if the incoming value is empty(""), the function returns true


var elm;
function isValidURL(u){
//A precaution/solution for the problem written in the ***note***
if(u!==""){
if(!elm){
elm = document.createElement('input');
elm.setAttribute('type', 'url');
}
elm.value = u;
return elm.validity.valid;
}
else{
return false
}
}


console.log(isValidURL(''));
console.log(isValidURL('http://www.google.com/'));
console.log(isValidURL('//google.com'));
console.log(isValidURL('google.com'));
console.log(isValidURL('localhost:8000'));

这个问题询问一个url验证方法,比如stackoverflow,主机名中没有协议或任何点。因此,这不是验证url sintax的问题,而是通过实际调用它来检查它是否是一个有效的url。

我尝试了几种方法来知道url是否真实存在,并且可以从浏览器中调用,但没有找到任何方法来测试javascript调用的响应头:

  • 添加一个锚元素可以触发click()方法。
  • 使用'GET'对具有挑战性的url进行ajax调用是可以的,但由于CORS策略,它有各种限制,并且不是使用ajax的情况,因为url可能在我的服务器域之外。
  • 使用获取API有一个类似ajax的解决方案。
  • 另一个问题是我的服务器在https协议下,并在调用非安全url时抛出异常。

所以,我能想到的最好的解决方案是得到一些工具来执行CURL使用javascript尝试类似curl -I <url>。不幸的是,我没有找到任何,在外观上,这是不可能的。我将感谢任何关于这一点的评论。

但是,最后,我有一个运行PHP的服务器,因为我几乎所有的请求都使用Ajax,所以我在服务器端写了一个函数来执行curl请求并返回到浏览器。

关于问题“stackoverflow”上的单个单词url,它将引导我到https://daniserver.com.ar/stackoverflow,其中daniserver.com.ar是我自己的域名。

这似乎是CS中最难的问题之一;)

这是另一个不完整的解决方案,它对我来说足够好,比我在这里看到的其他解决方案更好。为了支持IE11,我使用了一个输入[type=url],否则使用window会简单得多。URL来执行验证:

const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
function isValidIpv4(ip) {
if (!ipv4Regex.test(ip)) return false;
return !ip.split('.').find(n => n > 255);
}


const domainRegex = /(?:[a-z0-9-]{1,63}\.){1,125}[a-z]{2,63}$/i;
function isValidDomain(domain) {
return isValidIpv4(domain) || domainRegex.test(domain);
}


let input;
function validateUrl(url) {
if (! /^https?:\/\//.test(url)) url = `http://${url}`; // assuming Babel is used
// to support IE11 we'll resort to input[type=url] instead of window.URL:
// try { return isValidDomain(new URL(url).host) && url; } catch(e) { return false; }
if (!input) { input = document.createElement('input'); input.type = 'url'; }
input.value = url;
if (! input.validity.valid) return false;
const domain = url.split(/^https?:\/\//)[1].split('/')[0].split('@').pop();
return isValidDomain(domain) && url;
}


console.log(validateUrl('google'), // false
validateUrl('user:pw@mydomain.com'),
validateUrl('https://google.com'),
validateUrl('100.100.100.100/abc'),
validateUrl('100.100.100.256/abc')); // false

为了接受不完整的输入,例如“www.mydomain.com”,它还将使其有效,假设在这些情况下协议是“http”,如果地址有效,则返回有效的URL。无效时返回false。

它还支持IPv4域,但不支持IPv6域。

使用纯正则表达式很难做到这一点,因为url有很多“不方便”的地方。

  1. 例如域名对连字符有复杂的限制:

    a.中间允许有多个连续的连字符。

    B.域名的第一个字符和最后一个字符不能是连字符

    c.第3、4个字符不能同时为“-”

  2. 同样,端口号只能在1-65535之间。如果你提取端口部分并转换为int,这很容易检查,但很难用正则表达式检查。

  3. 也没有简单的方法来检查有效的域名扩展名。一些国家有二级域名(如'co.uk'),或者扩展名可以是一个长单词,如'.international'。新的顶级域名会定期添加。这类事情只能根据硬编码列表进行检查。(见https://en.wikipedia.org/wiki/Top-level_domain)

  4. 然后有磁铁网址,ftp地址等。这些都有不同的要求。

然而,这里有一个函数可以处理几乎所有的事情,除了:

  • 案例1。c
  • 接受任何1-5位数的端口号
  • 接受任何扩展2-13个字符
  • 不接受ftp,磁铁等…

function isValidURL(input) {
pattern = '^(https?:\\/\\/)?' + // protocol
'((([a-zA-Z\\d]([a-zA-Z\\d-]{0,61}[a-zA-Z\\d])*\\.)+' + // sub-domain + domain name
'[a-zA-Z]{2,13})' + // extension
'|((\\d{1,3}\\.){3}\\d{1,3})' + // OR ip (v4) address
'|localhost)' + // OR localhost
'(\\:\\d{1,5})?' + // port
'(\\/[a-zA-Z\\&\\d%_.~+-:@]*)*' + // path
'(\\?[a-zA-Z\\&\\d%_.,~+-:@=;&]*)?' + // query string
'(\\#[-a-zA-Z&\\d_]*)?$'; // fragment locator
regex = new RegExp(pattern);
return regex.test(input);
}


let tests = [];
tests.push(['', false]);
tests.push(['http://en.wikipedia.org/wiki/Procter_&_Gamble', true]);
tests.push(['https://sdfasd', false]);
tests.push(['http://www.google.com/url?sa=i&rct=j&q=&esrc=s&source=images&cd=&docid=nIv5rk2GyP3hXM&tbnid=isiOkMe3nCtexM:&ved=0CAUQjRw&url=http%3A%2F%2Fanimalcrossing.wikia.com%2Fwiki%2FLion&ei=ygZXU_2fGKbMsQTf4YLgAQ&bvm=bv.65177938,d.aWc&psig=AFQjCNEpBfKnal9kU7Zu4n7RnEt2nerN4g&ust=1398298682009707', true]);
tests.push(['https://stackoverflow.com/', true]);
tests.push(['https://w', false]);
tests.push(['aaa', false]);
tests.push(['aaaa', false]);
tests.push(['oh.my', true]);
tests.push(['dfdsfdsfdfdsfsdfs', false]);
tests.push(['google.co.uk', true]);
tests.push(['test-domain.MUSEUM', true]);
tests.push(['-hyphen-start.gov.tr', false]);
tests.push(['hyphen-end-.com', false]);
tests.push(['https://sdfasdp.international', true]);
tests.push(['https://sdfasdp.pppppppp', false]);
tests.push(['https://sdfasdp.ppppppppppppppppppp', false]);
tests.push(['https://sdfasd', false]);
tests.push(['https://sub1.1234.sub3.sub4.sub5.co.uk/?', true]);
tests.push(['http://www.google-com.123', false]);
tests.push(['http://my--testdomain.com', false]);
tests.push(['http://my2nd--testdomain.com', true]);
tests.push(['http://thingiverse.com/download:1894343', true]);
tests.push(['https://medium.com/@techytimo', true]);
tests.push(['http://localhost', true]);
tests.push(['localhost', true]);
tests.push(['localhost:8080', true]);
tests.push(['localhost:65536', true]);
tests.push(['localhost:80000', false]);
tests.push(['magnet:?xt=urn:btih:123', true]);


for (let i = 0; i < tests.length; i++) {
console.log('Test #' + i + (isValidURL(tests[i][0]) == tests[i][1] ? ' passed' : ' failed') + ' on ["' + tests[i][0] + '", ' + tests[i][1] + ']');
}

在我的情况下,我唯一的要求是,用户输入不会被解释为一个相对链接时,放置在一个标签的href和这里的答案要么有点OTT,要么允许url不符合我的要求,所以这就是我要做的:

^https?://.+$

没有正则表达式,同样的事情也可以很容易地实现。

这里只是一个非常简单的检查,以确保有一个有效的协议,并且域扩展名必须是两个或更多字符。

is_valid_url = ( $url ) => {


let $url_object = null;


try {
$url_object = new URL( $url );
} catch ( $error ) {
return false;
}


const $protocol = $url_object.protocol;
const $protocol_position = $url.lastIndexOf( $protocol );
const $domain_extension_position = $url.lastIndexOf( '.' );


return (
$protocol_position === 0 &&
[ 'http:', 'https:' ].indexOf( $protocol ) !== - 1 &&
$domain_extension_position > 2 && $url.length - $domain_extension_position > 2
);


};

和我一起工作

function isURL(str) {
var regex = /(http|https):\/\/(\w+:{0,1}\w*)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%!\-\/]))?/;
var pattern = new RegExp(regex);
return pattern.test(str);
}

使用validator.js

ES6

import isURL from 'validator/lib/isURL'


isURL(string)

没有ES6

var validator = require('validator');


validator.isURL(string)

你也可以通过传递可选的options对象作为isURL的第二个参数来微调这个函数的行为

下面是默认的options对象:

let options = {
protocols: [
'http',
'https',
'ftp'
],
require_tld: true,
require_protocol: false,
require_host: true,
require_valid_protocol: true,
allow_underscores: false,
host_whitelist: false,
host_blacklist: false,
allow_trailing_dot: false,
allow_protocol_relative_urls: false,
disallow_auth: false
}


isURL(string, options)

host_whitelisthost_blacklist可以是主机的数组。它们还支持正则表达式。

let options = {
host_blacklist: ['foo.com', 'bar.com'],
}


isURL('http://foobar.com', options) // => true
isURL('http://foo.bar.com/', options) // => true
isURL('http://qux.com', options) // => true


isURL('http://bar.com/', options) // => false
isURL('http://foo.com/', options) // => false




options = {
host_blacklist: ['bar.com', 'foo.com', /\.foo\.com$/],
}


isURL('http://foobar.com', options) // => true
isURL('http://foo.bar.com/', options) // => true
isURL('http://qux.com', options) // => true


isURL('http://bar.com/', options) // => false
isURL('http://foo.com/', options) // => false
isURL('http://images.foo.com/', options) // => false
isURL('http://cdn.foo.com/', options) // => false
isURL('http://a.b.c.foo.com/', options) // => false

如果你可以改变输入类型,我认为这个解决方案会更容易:

你可以简单地在输入中使用type="url",并在js中使用checkValidity()检查它

例句:

your.html

<input id="foo" type="url">

your.js

// The selector is JQuery, but the function is plain JS
$("#foo").on("keyup", function() {
if (this.checkValidity()) {
// The url is valid
} else {
// The url is invalid
}
});

这显然不是最有效的方法,但它是可读的,并且很容易形成您需要的任何形式。从这里添加regex/complexity更容易。这是一个非常实用的方法

const validFirstBits = ["ftp://", "http://", "https://", "www."];
const invalidPatterns = [" ", "//.", ".."];


export function isUrl(word) {
// less than www.1.dk
if (!word || word.length < 8) return false;


// Let's check and see, if our candidate starts with some of our valid first bits
const firstBitIsValid = validFirstBits.some(bit => word.indexOf(bit) === 0);
if (!firstBitIsValid) return false;


const hasInvalidPatterns = invalidPatterns.some(
pattern => word.indexOf(pattern) !== -1,
);


if (hasInvalidPatterns) return false;


const dotSplit = word.split(".");
if (dotSplit.length > 1) {
const lastBit = dotSplit.pop(); // string or undefined
if (!lastBit) return false;
const length = lastBit.length;
const lastBitIsValid =
length > 1 || (length === 1 && !isNaN(parseInt(lastBit)));
return !!lastBitIsValid;
}


return false;
}

测试:

import { isUrl } from "./foo";


describe("Foo", () => {
test("should validate correct urls correctly", function() {
const validUrls = [
"http://example.com",
"http://example.com/blah",
"http://127.0.0.1",
"http://127.0.0.1/wow",
"https://example.com",
"https://example.com/blah",
"https://127.0.0.1:1234",
"ftp://example.com",
"ftp://example.com/blah",
"ftp://127.0.0.1",
"www.example.com",
"www.example.com/blah",
];


validUrls.forEach(url => {
expect(isUrl(url) && url).toEqual(url);
});
});


test("should validate invalid urls correctly", function() {
const inValidUrls = [
"http:// foo.com",
"http:/foo.com",
"http://.foo.com",
"http://foo..com",
"http://.com",
"http://foo",
"http://foo.c",
];


inValidUrls.forEach(url => {
expect(!isUrl(url) && url).toEqual(url);
});
});
});

如果你也需要支持https://localhost:3000,那么使用[Devshed]s regex的修改版本。

    function isURL(url) {
if(!url) return false;
var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name
'((\\d{1,3}\\.){3}\\d{1,3}))|' + // OR ip (v4) address
'localhost' + // OR localhost
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
'(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
'(\\#[-a-z\\d_]*)?$', 'i'); // fragment locator
return pattern.test(url);
}

Mathias Bynens编译了一个带有测试url的知名URL regex列表。没有什么理由去写一个新的正则表达式;只要选择一个现有的最适合你的。

但是这些正则表达式的比较表也表明,使用单个正则表达式进行URL验证几乎是不可能的。Bynens列出的所有正则表达式都会产生假阳性和假阴性。

我建议您使用现有的URL解析器(例如JavaScript中的new URL('http://www.example.com/')),然后应用您想要对URL响应的解析和规范化形式执行的检查。它的组件。使用JavaScript URL接口还有一个额外的好处,它只接受浏览器真正接受的url。

您还应该记住,技术上不正确的url仍然可以工作。例如,http://w_w_w.example.com/http://www..example.com/http://123.example.com/都有一个无效的主机名部分,但我知道的每个浏览器都会试图打开它们而没有抱怨,当你在/etc/hosts/中为这些无效的名称指定IP地址时,这样的url甚至可以工作,但只在你的计算机上。

因此,问题不在于URL是否有效,而在于在特定的上下文中应该允许哪些URL工作。

如果你想进行URL验证,有很多细节和边缘情况很容易被忽视:

  • url可能包含http://user:password@www.example.com/中的凭据。
  • 端口号必须在0-65535的范围内,但是您可能仍然希望排除通配符端口0。
  • 端口号可能前导0,如http://www.example.com:000080/
  • IPv4地址不限制为4个十进制整数,取值范围为0 ~ 255。您可以使用1到4个整数,它们可以是十进制、八进制或十六进制。url https://010.010.000010.010/https://0x8.0x8.0x0008.0x8/https://8.8.2056/https://8.526344/https://134744072/都是有效的,只是编写https://8.8.8.8/的创造性方式。
  • 允许使用环回地址(http://127.0.0.1/)、私有IP地址(http://192.168.1.1)、链路本地地址(http://169.254.100.200)等可能会对安全性或隐私性产生影响。例如,如果你允许它们作为论坛中用户头像的地址,你会导致用户的浏览器在他们的本地网络中发送未经请求的网络请求,而在物联网中,这样的请求可能会在你的家中发生有趣或不那么有趣的事情。
  • 出于同样的原因,您可能希望放弃指向非完全限定主机名的链接,换句话说,就是不带点号的主机名。
  • 但主机名可能总是有一个尾随点(如http://www.stackoverflow.com.)。
  • 链接的主机名部分可以包含用于IPv6地址的尖括号,如http:// [:: 1)
  • IPv6地址也有专用网络或链路本地地址等范围。
  • 如果阻塞某些IPv4地址,请记住,例如https://127.0.0.1https://[::飞行符:127.0.0.1)指向相同的资源(如果您的机器的环回设备是IPv6就绪)。
  • url的主机名部分现在可能包含Unicode,因此字符范围[-0-9a-zA-z]肯定不再足够。
  • 许多顶级域的注册中心定义了特定的限制,例如允许的Unicode字符集。或者它们细分它们的名称空间(如co.uk和许多其他名称空间)。
  • 顶级域名不能包含十进制数字,并且不允许使用连字符,除非IDN a标签前缀“xn——”。
  • Unicode顶级域名(以及它们的punycode编码为“xn——”)仍然必须只包含字母,但谁想在正则表达式中检查它呢?

应用哪些限制和规则取决于项目需求和喜好。

我最近为一个web应用程序编写了一个URL验证器,它适用于论坛、社交网络等用户提供的URL。你可以把它作为你自己的基础:

我还写了一篇博客文章URL验证的血腥细节,有更深入的信息。

我将函数更改为Match +,在这里用斜杠和它的工作:(http://和https)进行更改

function isValidUrl(userInput) {
var res = userInput.match(/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g);
if(res == null)
return false;
else
return true;
}

有几个使用URL构造函数的测试,没有描述输入是字符串还是URL对象。

// Testing whether something is a URL
function isURL(url) {
return toString.call(url) === "[object URL]";
}


// Testing whether the input is both a string and valid url:
function isUrl(url) {
try {
return toString.call(url) === "[object String]" && !!(new URL(url));
} catch (_) {
return false;
}
}
< p > 2020更新。 为了扩展@iamnewton和@Fernando Chavez Herrera的精彩回答,我开始看到@被用于url的路径

所以更新后的正则表达式是:

RegExp('(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+@]*)*(\\?[;&a-z\\d%_.~+=-]*)?(\\#[-a-z\\d_]*)?$', 'i');

如果你想在查询字符串和哈希中允许它,使用:

RegExp('(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+@]*)*(\\?[;&a-z\\d%_.~+=-@]*)?(\\#[-a-z\\d_@]*)?$', 'i');

话虽如此,我不确定是否有白皮书规则禁止在查询字符串或哈希中使用@

已经有很多答案了,但这里有另一个贡献: 直接从URL polyfill有效性检查中提取,使用input元素和type="url"来利用浏览器内置的有效性检查:

var inputElement = doc.createElement('input');
inputElement.type = 'url';
inputElement.value = url;


if (!inputElement.checkValidity()) {
throw new TypeError('Invalid URL');
}

Source .

该功能不允许localhost,只允许web页面的url(即只允许http或https协议)。

它也只允许定义在这里的安全字符:https://www.urlencoder.io/learn/

function isValidWebUrl(url) {
let regEx = /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/gm;
return regEx.test(url);
}

您可以使用ajax请求来检查字符串是否有效的url和可访问的

(function() {






$("input").change(function() {


const check = $.ajax({
url : this.value,
dataType: "jsonp"
});


check.then(function() {
console.log("Site is valid and registered");
});


//expected output
check.catch(function(reason) {
if(reason.status === 200) {
return console.log("Site is valid and registered");
}
console.log("Not a valid site");
})


});


})()
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" placeholder="Please input url to check ? ">

另一种方法是使用Node.JS的DNS模块。

DNS模块提供了一种执行名称解析的方法,使用它可以验证url是否有效。

const dns = require('dns');
const url = require('url');


const lookupUrl = "https://stackoverflow.com";
const parsedLookupUrl = url.parse(lookupUrl);


dns.lookup(parsedLookupUrl.protocol ? parsedLookupUrl.host
: parsedLookupUrl.path, (error,address,family)=>{


console.log(error || !address ? lookupUrl + ' is an invalid url!'
: lookupUrl + ' is a valid url: ' + ' at ' + address);
    

}
);

这样您就可以检查url是否有效以及是否存在

我已经修改了所有的评论,注释和备注是这个主题,并做了一个新的正则表达式:

^((javascript:[\w-_]+(\([\w-_\s,.]*\))?)|(mailto:([\w\u00C0-\u1FFF\u2C00-\uD7FF-_]+\.)*[\w\u00C0-\u1FFF\u2C00-\uD7FF-_]+@([\w\u00C0-\u1FFF\u2C00-\uD7FF-_]+\.)*[\w\u00C0-\u1FFF\u2C00-\uD7FF-_]+)|(\w+:\/\/(([\w\u00C0-\u1FFF\u2C00-\uD7FF-]+\.)*([\w\u00C0-\u1FFF\u2C00-\uD7FF-]*\.?))(:\d+)?(((\/[^\s#$%^&*?]+)+|\/)(\?[\w\u00C0-\u1FFF\u2C00-\uD7FF:;&%_,.~+=-]+)?)?(#[\w\u00C0-\u1FFF\u2C00-\uD7FF-_]+)?))$

你可以在这里测试和改进https://regexr.com/668mt

我检查了下一个值的表达式:

http://www.google.com/url?sa=i&rct=j&q=&esrc=s&source=images&cd=&docid=nIv5rk2GyP3hXM&tbnid=isiOkMe3nCtexM:&ved=0CAUQjRw&url=http%3A%2F%2Fanimalcrossing.wikia.com%2Fwiki%2FLion&ei=ygZXU_2fGKbMsQTf4YLgAQ&bvm=bv.65177938,d.aWc&psig=AFQjCNEpBfKnal9kU7Zu4n7RnEt2nerN4g&ust=1398298682009707
http://192.168.0.4:55/
https://web.archive.org/web/20170817095211/https://github.com/Microsoft/vscode/issues/32405
http://www.example.com
javascript:void()
http://.
https://example.
https://en.m.wikipedia.org/wiki/C_Sharp_(programming_language)
http://zh.wikipedia.org/wiki/Wikipedia:关于中文维基百科/en?a#a
https://medium.com/@User_name/
https://test-test-test-test-test-test-test-test-test.web.app/
http://www.google.com/url?sa=i&rct=j&q=&esrc=s&source=images&cd=&docid=nIv5rk2GyP3hXM&tbnid=isiOkMe3nCtexM:&ved=0CAUQjRw&url=http%3A%2F%2Fanimalcrossing.wikia.com%2Fwiki%2FLion&ei=ygZXU_2fGKbMsQTf4YLgAQ&bvm=bv.65177938,d.aWc&psig=AFQjCNEpBfKnal9kU7Zu4n7RnEt2nerN4g&ust=1398298682009707
https://sdfasdp.ppppppppppp
mailto:sadf@gmail.com
https://тест.юа

这是@palvo的答案的扩展。

function isValidHttpUrl(string) {
let url;
try {
url = new URL(string);
} catch (_) {
return false;
}
return (url.protocol === "http:" || url.protocol === "https:") && (url.href == string || url.origin == string);
}

试试以下方法:-

  • isValidHttpUrl(“https:母羊/ dsdsd");
  • isValidHttpUrl(“https://ewe/dsdsd");

中测试

function isURL(_url)
{
let result = false;
let w = window;


if (!w._check_input)
{
let input = document.createElement("input");
input.type      = "url";
input.required  = true;


w._check_input = input;
}


w._check_input.value = _url;
if (w._check_input.checkValidity()) result = true;


return result;
}