检查JavaScript字符串是否为URL

时间:2011-04-19 13:26:56

标签: javascript string url

JavaScript中是否有办法检查字符串是否为URL?

排除了RegExes,因为该网址最有可能写成stackoverflow;也就是说它可能没有.comwwwhttp

34 个答案:

答案 0 :(得分:158)

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

答案 1 :(得分:86)

一个相关问题的回答:

Javascript regex URL matching

或来自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);
}

答案 2 :(得分:77)

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

当您设置href的{​​{1}}属性时,会设置各种其他属性。

anchor

source

但是,如果绑定的值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" 不是有效的url,则这些辅助属性的值将为空字符串。

编辑,如评论中所述:如果使用了无效的网址,则可以替换当前网址的属性。

所以,只要您没有传递当前页面的URL,就可以执行以下操作:

href

答案 3 :(得分:46)

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

const isValidUrl = (string) => {
  try {
    new URL(string);
    return true;
  } catch (_) {
    return false;  
  }
}

答案 4 :(得分:27)

使用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;
  }
}

答案 5 :(得分:24)

我使用以下函数验证带或不带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);
  if (res == null)
    return false;
  else
    return true;
};

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

答案 6 :(得分:22)

依靠图书馆: https://www.npmjs.com/package/valid-url

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

答案 7 :(得分:21)

对已接受答案的改进......

  • 检查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);
    }
    

答案 8 :(得分:11)

这是另一种方法。



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




答案 9 :(得分:8)

(我没有代表对ValidURL示例发表评论;因此将此作为答案发布。)

虽然不鼓励使用协议相对URL(The Protocol-relative 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的最佳方法。

答案 10 :(得分:6)

我无法评论最接近#5717133的帖子,但下面是我弄清楚如何让@ tom-gullen正则表达式工作的方式。

/^(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

答案 11 :(得分:5)

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

最好的提到:

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

来自Github segmentio/is-url。关于代码存储库的好处是你可以看到测试和任何问题以及测试字符串贯穿它。有一个分支允许字符串丢失google.com之类的协议,尽管你可能会做出太多的假设。 存储库已更新,我不打算在这里试图保持镜像。它已被分解为单独的测试,以避免可以被用于DOS攻击的RegEx redos(我不认为你必须担心客户端js,但你必须担心您的网页长时间停留以至于您的访问者离开了您的网站。

我还发现另一个存储库<{3}} 的甚至可能更适合isURL,但它非常复杂。它有一个更大的有效和无效URL测试列表。上面的简单结果仍然可以传递所有正数,但只能阻止像http://a.b--c.de/这样的奇数负数以及特殊的ips。

无论您选择哪种方式,都可以通过此功能运行它,我已经使用您的浏览器的开发人员工具操作员在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"));}

然后测试那串&#39; a。

在发布看似很棒的正则表达式之前,请参阅Mathias Bynens的dperini/regex-weburl.js以获取更多信息。

答案 12 :(得分:4)

我用来验证网址“字符串”的一个功能是:

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

答案 13 :(得分:4)

您可以使用URL native API

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

答案 14 :(得分:2)

已经有很多答案,但这是另一个贡献: 直接从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

答案 15 :(得分:2)

这和我一起工作

logfile = 'Datalog'+currtime+'.log'
logging.basicConfig(filename=logfile,level=logging.DEBUG,format='%(asctime)s %(message)s', datefmt='%d/%m/%Y %H:%M:%S')
logging.info(file+' is processed successfully')

答案 16 :(得分:2)

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

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

    a。中间可以有很多连续的连字符。

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

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

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

  3. 也没有简便的方法来检查有效的域扩展名。有些国家/地区带有second-level domains(例如'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] + ']');
}

答案 17 :(得分:1)

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

^https?://.+$

无需正则表达式就可以轻松实现同一件事。

答案 18 :(得分:1)

该问题询问了诸如stackoverflow之类的网址的验证方法,没有主机名中的协议或任何点。所以,这不是验证url sintax的问题​​,而是通过实际调用它来检查它是否是一个有效的URL。

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

  • 添加锚元素可以用于触发click()方法。
  • 使用'GET'对具有挑战性的网址进行ajax调用很好,但是由于CORS政策而导致其存在各种限制,并且不是使用ajax的情况,因为网址是也许在我服务器的域外。
  • 使用fetch API的解决方法类似于ajax。
  • 其他问题是我的服务器位于https协议下,并在调用非安全网址时抛出异常。

因此,我能想到的最佳解决方案是使用javascript尝试类似CURL的内容来获取curl -I <url>的工具。不幸的是,我没有找到任何,并且在外观上它是不可能的。我将对此表示感谢。

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

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

答案 19 :(得分:1)

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

您可以在输入中简单使用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
    }
});

答案 20 :(得分:1)

这绝对不是最有效的方法,但是它可读性强,易于根据您的需要形成。从这里添加正则表达式/复杂性会更容易。所以这是一个非常实用的方法

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

答案 21 :(得分:1)

此功能禁止本地主机,并且仅允许网页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);
}

答案 22 :(得分:1)

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

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

我建议您使用现有的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/的主机名部分都无效,但是我知道的每个浏览器都将尝试打开它们而不会引起投诉,并且当您在{中为这些无效名称指定IP地址时{1}}这样的URL甚至可以在您的计算机上使用。

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

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

  • URL可能包含/etc/hosts/中的凭据。
  • 端口号必须在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://user:password@www.example.com/中)。
  • 链接的主机名部分可能包含IPv6地址的尖括号,如http://[::1]中一样。
  • IPv6地址还具有专用网络或链接本地地址等的范围。
  • 如果您阻止某些IPv4地址,请记住,例如https://127.0.0.1https://[::ffff:127.0.0.1]指向相同的资源(如果您的计算机的回送设备已准备好IPv6)。
  • URL的主机名部分现在可能包含Unicode,因此字符范围http://www.stackoverflow.com.绝对不再足够。
  • 许多顶级域的注册表都定义了特定的限制,例如在允许的Unicode字符集上。或者,他们细分其名称空间(例如[-0-9a-zA-z]和许多其他名称空间)。
  • 顶级域不得包含十进制数字,除非IDN A标签前缀为“ xn--”,否则不允许使用连字符。
  • Unicode顶级域(及其带有“ xn--”的punycode编码)仍必须仅包含字母,但是谁想在正则表达式中进行检查?

这些限制和规则中的哪些是项目要求和品味的问题。

我最近写了一个Web应用程序的URL验证器,它适用于论坛,社交网络等中用户提供的URL。随意将其用作自己的基础:

我还写了一篇博客文章The Gory Details of URL Validation,其中包含更深入的信息。

答案 23 :(得分:1)

我将功能更改为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;
}

答案 24 :(得分:1)

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

话虽这么说,但我不确定是否有白皮书规则禁止查询字符串或哈希中的@

答案 25 :(得分:0)

另一种方法是使用 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 是否有效以及它是否存在

答案 26 :(得分:0)

这似乎是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。

答案 27 :(得分:0)

您可以使用 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 ? ">

答案 28 :(得分:0)

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

//cdn.google.com/script.js

我们可以事先添加缺少的协议以避免这种情况。它也无法检测到以下无效网址。

http://w
http://..

那么为什么检查整个网址?我们可以查看域名。我借用了正则表达式来验证来自here的域名。

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

答案 29 :(得分:0)

有一些使用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;  
    }
}

答案 30 :(得分:0)

如果您还需要支持https://localhost:3000,请使用此[Devshed]正则表达式的修改版本。

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

答案 31 :(得分:0)

使用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

答案 32 :(得分:0)

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

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

};

答案 33 :(得分:-1)

const isValidURL = url => {
    if(String(url) !== url) return false
    const regex = /(https?:\/\/)?(www\.)?\w{2,}(\.\w{2,}){1,}/g,
    didMatch = url.match(regex)
    return Array.isArray(didMatch)
}

const isValidURL = url => {
    if(String(url) !== url) return false
	const regex = /(https?:\/\/)?(www\.)?\w{2,}(\.\w{2,}){1,}/g,
    didMatch = url.match(regex)
    return Array.isArray(didMatch)
}

// expectToBeTrue
console.log(isValidURL('example.com'))
console.log(isValidURL('http://example.com'))
console.log(isValidURL('https://example.com'))
console.log(isValidURL('http://example.com.org'))
console.log(isValidURL('http://subdomain.example.com'))
console.log(isValidURL('https://subdomain.example.com'))

// expectToBeFalse
console.log(isValidURL('example'))
console.log(isValidURL('http://example'))
console.log(isValidURL([]))
console.log(isValidURL(''))