Подтвердить что ты не робот

Проверьте, является ли строка JavaScript URL

Есть ли в JavaScript способ проверить, является ли строка URL-адресом?

RegExes исключены, потому что URL, скорее всего, написан как stackoverflow; то есть он может не иметь .com, www или http.

4b9b3361

Ответ 1

Смежный вопрос с ответом:

Соответствие URL регулярного выражения 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);
}

Ответ 2

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

Ответ 3

Вместо использования регулярного выражения я бы рекомендовал использовать якорный элемент.

когда вы устанавливаете свойство 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);
}

Ответ 4

Вы можете попробовать использовать URL конструктор: если он не выбрасывает, строка является допустимым URL:

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

Термин "URL" определен в RFC 3886 (как URI); оно должно начинаться с имени схемы, а имя схемы не ограничивается http/https.

Известные примеры:

  • www.google.com недействительный URL (отсутствует схема)
  • javascript:void(0) является действительным URL, но не HTTP
  • http://.. является допустимым URL-адресом, где хостом является ..; разрешается ли он, зависит от вашего DNS
  • https://google..com действительный URL, такой же как выше

Ответ 5

Я использую функцию ниже для проверки URL с или без http/https:

function isValidURL(string) {
  var res = string.match(/(http(s)?:\/\/.)?(www\.)?[[email protected]:%._\+~#=]{2,256}\.[a-z]{2,6}\b([[email protected]:%_\+.~#?&//=]*)/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

Ответ 6

Чтобы проверить URL-адрес, используя 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;
  }
}

Ответ 7

Полагайтесь на библиотеку: https://www.npmjs.com/package/valid-url

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

Ответ 8

Улучшение принятого ответа...

  • Проверьте 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);
    }
    

Ответ 9

Вот еще один метод.

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

Ответ 10

(У меня нет представителей, чтобы комментировать пример ValidURL; поэтому опубликуйте это как ответ.)

Хотя использование относительных к протоколу URL не рекомендуется (относящиеся к протоколу URL), они иногда работают. Чтобы проверить такой URL с помощью регулярного выражения, часть протокола может быть необязательной, например:

function isValidURL(str) {
    var pattern = new RegExp('^((https?:)?\\/\\/)?'+ // protocol
        '(?:\\S+(?::\\S*)[email protected])?' + // 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-адресов.

Ответ 11

Я не могу прокомментировать сообщение, которое является ближайшим # 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

Ответ 12

Как уже отмечалось, идеальное регулярное выражение неуловимо, но все же кажется разумным подходом (альтернативы - тесты на стороне сервера или новый экспериментальный URL API). Однако высокопоставленные ответы часто возвращают false для обычных URL-адресов, но, что еще хуже, ваше приложение/страница будет isURL('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') на несколько минут даже на такой простой строке, как isURL('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'). На это было указано в некоторых комментариях, но, скорее всего, для его просмотра не было введено неправильное значение. Такое зависание делает этот код непригодным для использования в любом серьезном приложении. Я думаю, что из-за повторяющихся нечувствительных к регистру множеств в коде, как ((([az\\d]([az\\d-]*[az\\d])*)\\.?)+[az]{2,}|'... Извлеките' я ', и оно не зависнет, но, конечно, не будет работать должным образом. Но даже с флагом игнорирования регистра эти тесты отклоняют допустимые высокие значения Юникода.

Лучшее уже упоминалось:

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

Это происходит от Github segmentio/is-url. Хорошая вещь о репозитории кода - вы можете видеть тестирование и любые проблемы, а также тестовые строки, проходящие через него. Есть ветка, которая позволила бы пропустить строки без протокола, например google.com, хотя вы, вероятно, делаете слишком много предположений. Хранилище было обновлено, и я не собираюсь пытаться держать зеркало здесь. Он был разбит на отдельные тесты, чтобы избежать повторов RegEx, которые могут быть использованы для DOS-атак (я не думаю, что вам придется беспокоиться об этом с js на стороне клиента, но вам действительно нужно беспокоиться о том, что ваша страница зависает так долго, что ваш посетитель покидает ваш сайт).

Я видел еще один репозиторий, который может быть даже лучше для isURL в dperini/regex-weburl.js, но он очень сложный. Он имеет больший тестовый список действительных и недействительных URL. Простой, приведенный выше, по-прежнему пропускает все позитивы и не может блокировать только несколько нечетных негативов, таких как http://ab--c.de/ а также специальные ips.

Независимо от того, что вы выберете, запустите его через эту функцию, которую я адаптировал из тестов dperini/regex-weburl.js, используя в вашем браузере Inpector Developer Tools.

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:[email protected]:8080"));
console.assert(isURL("http://userid:[email protected]:8080/"));
console.assert(isURL("http://[email protected]"));
console.assert(isURL("http://[email protected]/"));
console.assert(isURL("http://[email protected]:8080"));
console.assert(isURL("http://[email protected]:8080/"));
console.assert(isURL("http://userid:[email protected]"));
console.assert(isURL("http://userid:[email protected]/"));
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:[email protected]:5702/db"));
console.assert(isURL("https://[email protected]/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"));}

А затем проверить эту строку "а".

Посмотрите это сравнение регулярного выражения isURL от Mathias Bynens для получения дополнительной информации, прежде чем публиковать, казалось бы, замечательное регулярное выражение.

Ответ 13

Вы можете использовать собственный API URL:

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

Ответ 14

Одна функция, которую я использовал для проверки 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

Ответ 15

Это довольно сложно сделать с чистым регулярным выражением, потому что URL-адреса имеют много "неудобств".

  1. Например, доменные имена имеют сложные ограничения на дефисы:

    а. Разрешено иметь много последовательных дефисов в середине.

    б. но первый и последний символ имени домена не может быть дефисом

    с. 3-й и 4-й символ не может быть дефисом

  2. Точно так же номер порта может быть только в диапазоне 1-65535. Это легко проверить, если вы извлекаете часть порта и конвертируете в int но довольно сложно проверить с помощью регулярного выражения.

  3. Также нет простого способа проверить действительные доменные расширения. В некоторых странах есть домены второго уровня (например, "co.uk"), или расширение может быть длинным словом, например ".international". И новые TLD добавляются регулярно. Этот тип вещей может быть проверен только по жестко закодированному списку. (см. https://en.wikipedia.org/wiki/Top-level_domain)

  4. Кроме того, существуют URL-адреса, адреса FTP и т.д. Все они имеют разные требования.

Тем не менее, вот функция, которая обрабатывает почти все, кроме:

  • Случай 1. с
  • Принимает любой 1-5-значный номер порта
  • Принимает любое продление 2-13 символов
  • Не принимает фтп, магнит и т.д...

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] + ']');
}

Ответ 16

Вопрос задает метод проверки для URL-адреса, такого как stackoverflow, без протокола или какой-либо точки в имени хоста. Таким образом, дело не в проверке синтаксиса URL, а в проверке, является ли он действительным, путем его фактического вызова.

Я попробовал несколько способов узнать, существует ли URL-адрес истина и может ли он вызываться из браузера, но не нашел способа проверить с помощью javascript заголовок ответа на вызов:

  • добавление элемента привязки прекрасно для запуска метода click().
  • делать вызов ajax на вызывающий URL с помощью 'GET' хорошо, но он имеет различные ограничения из-за политик CORS, и это не тот случай использования ajax, поскольку в качестве URL может быть любой другой домен вне моего сервера.
  • использование API извлечения имеет обходной путь, похожий на ajax.
  • Другая проблема заключается в том, что мой сервер работает по протоколу https и выдает исключение при вызове незащищенных URL-адресов.

Итак, лучшее решение, которое я могу придумать, - это получить какой-нибудь инструмент для выполнения CURL с использованием javascript, попробовав что-то вроде curl -I <url>. К сожалению, я не нашел ни одного и на первый взгляд это невозможно. Буду признателен за любые комментарии по этому вопросу.

Но, в конце концов, у меня есть сервер, на котором работает PHP и, поскольку я использую Ajax почти для всех своих запросов, я написал функцию на стороне сервера, чтобы выполнить там запрос curl и вернуться в браузер.

Что касается отдельного слова url в вопросе "stackoverflow", это приведет меня к https://daniserver.com.ar/stackoverflow, где daniserver.com.ar - мой собственный домен.

Ответ 17

В моем случае мое единственное требование состоит в том, чтобы пользовательский ввод не интерпретировался как относительная ссылка, если он помещен в href тега, и ответы здесь были либо немного OTT для этого, либо разрешенные URL не соответствуют моим требованиям, поэтому это это то, что я собираюсь с:

^https?://.+$

То же самое может быть достигнуто довольно легко без регулярных выражений.

Ответ 18

это работает со мной

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

Ответ 19

Если вы можете изменить тип ввода, я думаю, что это решение будет намного проще:

Вы можете просто использовать 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
    }
});

Ответ 20

Это демонстративно не самый эффективный подход, но он легко читается и легко поддается формированию. И здесь проще добавить регулярное выражение/сложность. Так что здесь очень прагматичный подход

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

TEST:

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

Я думаю, что использование нативного 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 и надеюсь, что он начнет поддерживать все в ближайшем будущем.

Ответ 22

Кажется, это одна из самых сложных проблем в 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:[email protected]'),
  validateUrl('https://google.com'),
  validateUrl('100.100.100.100/abc'),
  validateUrl('100.100.100.256/abc')); // false

Ответ 23

Здесь просто очень простая проверка, чтобы убедиться в наличии действующего протокола, а расширение домена должно состоять из двух или более символов.

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

};

Ответ 24

Используйте 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