Проверьте, является ли строка JavaScript URL - PullRequest
194 голосов
/ 19 апреля 2011

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

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

Ответы [ 22 ]

6 голосов
/ 20 марта 2014

Я не могу комментировать пост, который является самым близким # 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
5 голосов
/ 09 марта 2018

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

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

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-weburl.js , но он очень сложный. Он имеет больший тестовый список действительных и недействительных 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"));}

А затем проверьте эту строку 'a's.

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

5 голосов
/ 14 марта 2018

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

  const isUrl = string => {
      try { return Boolean(new URL(string)); }
      catch(e){ return false; }
  }
4 голосов
/ 31 января 2018

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

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

function isURL(str) {
  var regex = /(http|https):\/\/(\w+:{0,1}\w*)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%!\-\/]))?/;
  var pattern = new RegExp(regex); 
return pattern.test(str);
}
2 голосов
/ 10 февраля 2019

Это довольно сложно сделать с чистым регулярным выражением, потому что у 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] + ']');
}
1 голос
/ 25 марта 2019

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

^https?://.+$

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

1 голос
/ 22 апреля 2018

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

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

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

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

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

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

0 голосов
/ 22 июня 2019

Использование 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
0 голосов
/ 02 апреля 2019

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

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

};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...