How to test if a URL string is absolute or relative?

后端 未结 16 1300
甜味超标
甜味超标 2020-11-29 20:05

How can I test a URL if it is a relative or absolute path in Javascript or jQuery? I want to handle accordingly depending if the passed in URL is a local or external path.

相关标签:
16条回答
  • 2020-11-29 20:39

    It should not start with a slash or hash, and it should not contain a double slash if not preceded by question mark or hash? I would not test that with a single regexp, it would be very complicated to match "no double slash".

    function test(s) {
        return s.charAt(0) != "#"
          && s.charAt(0) != "/"
          && ( s.indexOf("//") == -1 
            || s.indexOf("//") > s.indexOf("#")
            || s.indexOf("//") > s.indexOf("?")
        );
    }
    

    would be easier, clearer and imho faster.

    0 讨论(0)
  • 2020-11-29 20:40

    Depending on your needs, I think that a more reliable way to determine this is to use the built-in URL interface to construct a couple URL objects and compare origins.

    new URL(document.baseURI).origin === new URL(urlToTest, document.baseURI).origin;
    

    This allows the browser to parse and figure all this out for you, without having to worry about the side effects of edge cases.

    0 讨论(0)
  • 2020-11-29 20:41

    Neither of the mentioned solutions solved a redirect_url hack where the hacker entered /\/example.com or /\\/example.com. This is what I came up with to determine if our redirect url was relative:

    var isRelative = !redirectUrl.match(/(\:|\/\\*\/)/);  // Don't allow "//" (with optional "\"'s) or ":"
    
    0 讨论(0)
  • 2020-11-29 20:44
    var pat = /^https?:\/\//i;
    if (pat.test(urlString))
    {
        //do stuff
    }
    

    For protocol relative urls, use this regex:

    /^https?:\/\/|^\/\//i

    0 讨论(0)
  • 2020-11-29 20:44

    Original Answer

    A very fast and very flexible check is:

    if (url.indexOf('://') > 0 || url.indexOf('//') === 0 ) {
        // URL is absolute; either "http://example.com" or "//example.com"
    } else {
        // URL is relative
    }
    

    This will recognize an absolute URL, if:

    • URL contains "://" anywhere after the first character, or
    • URL starts with "//" (protocol relative)

    • No regex.
    • No jQuery or other dependency.
    • No hardcoded protocol names that make the condition case sensitive.
    • No string manipulation (e.g. toLowerCase or similar).
    • Only checks for "relative or absolute" but does not make any other sanity checks, can be used for web URLs or any internal protocol.

    Update 1 (full function example)

    Here is a quick function that returns true/false for the given URL:

    function isUrlAbsolute(url) { 
        return (url.indexOf('://') > 0 || url.indexOf('//') === 0);
    }
    

    And same in ES6:

    const isUrlAbsolute = (url) => (url.indexOf('://') > 0 || url.indexOf('//') === 0)
    

    Update 2 (URLs inside URL param)

    To additionally address URLs in format /redirect?target=http://example.org I recommend to use this code:

    function isUrlAbsolute(url) {
        if (url.indexOf('//') === 0) {return true;} // URL is protocol-relative (= absolute)
        if (url.indexOf('://') === -1) {return false;} // URL has no protocol (= relative)
        if (url.indexOf('.') === -1) {return false;} // URL does not contain a dot, i.e. no TLD (= relative, possibly REST)
        if (url.indexOf('/') === -1) {return false;} // URL does not contain a single slash (= relative)
        if (url.indexOf(':') > url.indexOf('/')) {return false;} // The first colon comes after the first slash (= relative)
        if (url.indexOf('://') < url.indexOf('.')) {return true;} // Protocol is defined before first dot (= absolute)
        return false; // Anything else must be relative
    }
    

    And the same in short form and ES 6

    // Traditional JS, shortened
    function isUrlAbsolute(url) {
        return url.indexOf('//') === 0 ? true : url.indexOf('://') === -1 ? false : url.indexOf('.') === -1 ? false : url.indexOf('/') === -1 ? false : url.indexOf(':') > url.indexOf('/') ? false : url.indexOf('://') < url.indexOf('.') ? true : false;
    }
    
    // ES 6
    const isUrlAbsolute = (url) => (url.indexOf('//') === 0 ? true : url.indexOf('://') === -1 ? false : url.indexOf('.') === -1 ? false : url.indexOf('/') === -1 ? false : url.indexOf(':') > url.indexOf('/') ? false : url.indexOf('://') < url.indexOf('.') ? true : false)
    

    Here are some test cases:

    // Test
    console.log( isUrlAbsolute('http://stackoverflow.com') ) // -> true
    console.log( isUrlAbsolute('//stackoverflow.com') ) // -> true
    console.log( isUrlAbsolute('stackoverflow.com') ) // -> false
    console.log( isUrlAbsolute('Ftp://example.net') ) // -> true
    console.log( isUrlAbsolute('/redirect?target=http://example.org') ) // -> false
    

    Update 3 (clarify relative URLs)

    I've seen a few comments about invalid output:

    • Solution returns false for localhost
    • Answer fails on http:example.com

    However, those URLs are indeed relative URLs. It's easy to test:

    1. Create some folders on your localhost webroot, say a/b/c/
    2. Create an index.html file and place following link into it: <a href="localhost">test</a>
    3. Open the index page in your browser: http://localhost/a/b/c/index.html and click on the link. You will end on http://localhost/a/b/c/localhost (and not on http://localhost)
    4. Same happens when placing the link http:example.com into your index.html file. You end on http://localhost/a/b/c/example.com instead of http://example.com
    0 讨论(0)
  • 2020-11-29 20:44
    var adress = 'http://roflmao.com';
    if (adress.substr(0,7) == 'http://' || adress.substr(0,8) == 'https://') {
        //
    }
    
    0 讨论(0)
提交回复
热议问题