Check if a JavaScript string is a URL

前端 未结 30 2872
野趣味
野趣味 2020-11-22 15:41

Is there a way in JavaScript to check if a string is a URL?

RegExes are excluded because the URL is most likely written like stackoverflow; that is to s

相关标签:
30条回答
  • 2020-11-22 16:22

    There's a lot of answers already, but here's another contribution: Taken directly from the URL polyfill validity check, use an input element with type="url" to take advantage of the browser's built-in validity check:

    var inputElement = doc.createElement('input');
    inputElement.type = 'url';
    inputElement.value = url;
    
    if (!inputElement.checkValidity()) {
        throw new TypeError('Invalid URL');
    }
    

    Source

    0 讨论(0)
  • 2020-11-22 16:22

    I think using the native URL API is better than a complex regex patterns as @pavlo suggested. It has some drawbacks though which we can fix by some extra code. This approach fails for the following valid url.

    //cdn.google.com/script.js
    

    We can add the missing protocol beforehand to avoid that. It also fails to detect following invalid url.

    http://w
    http://..
    

    So why check the whole url? we can just check the domain. I borrowed the regex to verify domain from 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;
        }
    }
    

    The hostname attribute is empty string for javascript:void(0), so it works for that too, and you can also add IP address verifier too. I'd like to stick to native API's most, and hope it starts to support everything in near future.

    0 讨论(0)
  • 2020-11-22 16:23

    Here is yet another method.

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

    0 讨论(0)
  • 2020-11-22 16:24

    In my case my only requirement is that the user input won't be interpreted as a relative link when placed in the href of an a tag and the answers here were either a bit OTT for that or allowed URLs not meeting my requirements, so this is what I'm going with:

    ^https?://.+$
    

    The same thing could be achieved pretty easily without regex.

    0 讨论(0)
  • 2020-11-22 16:25

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

    As others noted, regular expression does not seem to be the best suited approach for validating URLs, though.

    0 讨论(0)
  • 2020-11-22 16:30

    This is defiantly not the most effective approach, but it is readable and easy to form to whatever you need. And it's easier to add regex/complexity from here. So here is a very pragmatic approach

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

    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);
            });
        });
    });
    
    0 讨论(0)
提交回复
热议问题