检查JavaScript字符串是否为URL

2020/10/04 10:41 · javascript ·  · 0评论

JavaScript中是否可以检查字符串是否为URL?

正则表达式被排除在外,因为URL的写法很像stackoverflow也就是说,它可能没有.comwww或者http

与答案相关的问题:

JavaScript正则表达式网址匹配

或来自Devshed的此正则表达式

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);
}

您可以尝试使用URL构造函数:如果不抛出,则该字符串是有效的URL:

function isValidUrl(string) {
  try {
    new URL(string);
  } catch (_) {
    return false;  
  }

  return true;
}

术语“ URL”在RFC 3886中定义为URI。它必须以方案名称开头,并且方案名称不限于http / https。

著名的例子:

  • www.google.com 网址无效(丢失方案)
  • javascript:void(0) 是有效的网址,尽管不是HTTP网址
  • http://..是有效的URL,主机..; 是否解析取决于您的DNS
  • https://google..com 是有效的网址,与上面相同

如果要检查字符串是否为有效的HTTP URL:

function isValidHttpUrl(string) {
  let url;

  try {
    url = new URL(string);
  } catch (_) {
    return false;  
  }

  return url.protocol === "http:" || url.protocol === "https:";
}
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);
}

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

当您设置的href属性时,还会设置anchor其他各种属性。

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"

资源

但是,如果href绑定的值不是有效的url,则这些辅助属性的值将为空字符串。

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

因此,只要您不传递当前页面的URL,就可以执行以下操作:

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

我正在使用以下功能来验证带有或不带有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

使用JavaScript验证网址如下所示

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

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

import { isWebUri } from 'valid-url';
// ...
if (!isWebUri(url)) {
    return "Not a valid 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);
    }
    

这是另一种方法。

var elm;
function isValidURL(u){
  if(!elm){
    elm = document.createElement('input');
    elm.setAttribute('type', 'url');
  }
  elm.value = u;
  return elm.validity.valid;
}

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

(I don't have reps to comment on ValidURL example; hence post this as an answer.)

While use of protocol relative URLs is not encouraged (The Protocol-relative URL), they do get employed sometimes. To validate such an URL with a regular expression the protocol part could be optional, e.g.:

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的方法。

您可以使用URL本机API

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

如前所述,完美的正则表达式是难以捉摸的,但似乎仍然是一种合理的方法(替代方法是服务器端测试或新的实验性URL API)。但是,对于通用网址,排名靠前的答案通常会返回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重做可被DOS攻击利用,已将拆分为单独的测试(我认为您不必担心客户端js会担心这一点,但是您确实需要担心页面挂了这么长时间以至于您访客离开您的网站)。

我见过另外一个存储库,dperini / regex-weburl.js中对于isURL可能甚至更好,但是它非常复杂。它具有更大的有效和无效URL测试列表。上面简单的一个仍然可以传递所有正数,并且只能阻止一些奇数负数http://a.b--c.de/以及特殊ip。

无论您选择哪种方式,都可以使用浏览器的“开发人员工具”检查器通过此功能运行该功能,该功能已根据dperini / regex-weburl.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 regex进行的比较,以获取更多信息。

我无法评论离#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

我用来验证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有很多“不便”。

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

    一种。中间可以有许多连续的连字符。

    b。但域名的第一个字符和最后一个字符不能为连字符

    C。第三个和第四个字符不能都是连字符

  2. 同样,端口号只能在1-65535范围内。如果您提取端口部分并将其转换为,这很容易检查,int但是使用正则表达式很难检查。

  3. 也没有简单的方法来检查有效的域扩展名。一些国家/地区具有二级域名(例如'co.uk'),或者扩展名可以是一个长词,例如'.international'。并定期添加新的TLD。此类内容只能通过硬编码列表进行检查。(请参阅https://en.wikipedia.org/wiki/Top-level_domain

  4. 然后是磁铁URL,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] + ']');
}

使用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_whitelist并且host_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

这和我一起工作

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

如果您可以更改输入类型,我认为此解决方案会容易得多:

您可以type="url"在输入中简单使用,并checkValidity()在js中进行检查

例如:

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
    }
});

已经有很多答案,但是这是另外一个贡献:直接来自URLpolyfill有效性检查,使用带有input元素type="url"来利用浏览器的内置有效性检查:

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

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

资源

我认为使用本地URL API优于@pavlo建议的复杂正则表达式模式。它有一些缺点,但是我们可以通过一些额外的代码来解决。对于以下有效网址,此方法将失败。

//cdn.google.com/script.js

我们可以预先添加缺少的协议以避免这种情况。它还无法检测到以下无效的URL。

http://w
http://..

那么,为什么要检查整个网址?我们可以只检查域。我借用了正则表达式从这里验证域

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,并希望它在不久的将来开始支持所有功能。

该问题要求一种验证方法来查询url之类的网址stackoverflow,而不使用协议或主机名中的任何点。因此,验证URL sintax不是问题,而是通过实际调用来检查它是否为有效URL。

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

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

因此,我能想到的最好的解决方案是CURL使用javascript尝试一些工具来执行某些工具curl -I <url>不幸的是,我没有找到任何东西,而且看起来不可能。我对此表示感谢。

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

关于“ stackoverflow”问题上的单个网址,它将带我到https://daniserver.com.ar/stackoverflow,daniserver.com.ar是我自己的域。

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

这是另一种不完整的解决方案,对我来说效果很好,并且比我在这里看到的其他解决方案更好。我为此使用input [type = url]来支持IE11,否则使用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。

在我的情况下,我唯一的要求是,将用户输入放置在标签的href中时,用户输入不会被解释为相对链接,并且此处的答案要么是OTT,要么是所允许的URL不符合我的要求,因此我要用的是:

^https?://.+$

不用正则表达式就可以很容易地实现同一件事。

显然,这不是最有效的方法,但是它易于阅读,并且易于形成您所需的任何内容。从这里添加正则表达式/复杂性会更容易。所以这是一个非常务实的方法

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);
        });
    });
});

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

但是,这些正则表达式的比较表还显示,几乎不可能使用单个正则表达式进行URL验证。Bynens列表中的所有正则表达式都会产生误报和误报。

我建议您使用现有的URL解析器(例如,new URL('http://www.example.com/')在JavaScript中),然后对要解析的URL解析形式和规范化形式应用要执行的检查。它的组件。使用JavaScriptURL界面的另一个好处是,它将仅接受浏览器真正接受的URL。

您还应该记住,技术上不正确的URL仍然可以使用。例如http://w_w_w.example.com/http://www..example.com/http://123.example.com/都有一个无效的主机名的一部分,但每次我都知道浏览器将尝试打开它们无投诉,当你在这些无效名称指定IP地址/etc/hosts/等的URL,甚至会工作,但只在您的计算机上。

因此,问题不仅仅在于URL是否有效,而在于在特定上下文中哪些URL有效并且应该被允许。

如果您想进行URL验证,那么有很多细节和边缘情况很容易忽略:

  • 网址可能包含中的凭据http://user:password@www.example.com/
  • 端口号必须在0-65535的范围内,但是您可能仍要排除通配符端口0。
  • http://www.example.com:000080/一样,端口号可能带有前导零
  • IPv4地址绝不限于0-255范围内的4个十进制整数。您可以使用1-4个整数,它们可以是十进制,八进制或十六进制。该网址的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:// [:: ffff:127.0.0.1]指向相同的资源(如果计算机的回送设备已准备好IPv6) )。
  • URL的主机名部分现在可能包含Unicode,因此字符范围[-0-9a-zA-z]肯定不再足够。
  • 许多顶级域的注册表都定义了特定的限制,例如在允许的Unicode字符集上。或者,它们可以细分其名称空间(例如co.uk和许多其他名称空间)。
  • 顶级域不得包含十进制数字,除非IDN A标签前缀为“ xn--”,否则不允许使用连字符。
  • Unicode顶级域(及其带有“ xn--”的punycode编码)仍必须仅包含字母,但是谁想在正则表达式中进行检查?

这些限制和规则中的哪个适用于项目要求和偏好。

我最近为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;
}

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(即,仅允许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);
}

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

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
    );

};

如果您还需要支持,请https://localhost:3000使用[Devshed] 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);
    }
本文地址:http://javascript.askforanswer.com/jianchajavascriptzifuchuanshifouweiurl.html
文章标签: ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!