94

如果 URL 是 Javascript 或 jQuery 中的相对或绝对路径,我如何测试它?我想根据传入的 URL 是本地路径还是外部路径进行相应处理。

if (urlString starts with http:// or https://)
 //do this
4

16 回答 16

199

快速地

如果您只需要测试http://orhttps://那么最有效的方法是:

if (urlString.indexOf('http://') === 0 || urlString.indexOf('https://') === 0)

普遍的

但是,我会建议一种更通用、不区分大小写、与协议无关的方法:

var r = new RegExp('^(?:[a-z]+:)?//', 'i');
r.test('http://example.com'); // true - regular http absolute URL
r.test('HTTP://EXAMPLE.COM'); // true - HTTP upper-case absolute URL
r.test('https://www.exmaple.com'); // true - secure http absolute URL
r.test('ftp://example.com/file.txt'); // true - file transfer absolute URL
r.test('//cdn.example.com/lib.js'); // true - protocol-relative absolute URL
r.test('/myfolder/test.txt'); // false - relative URL
r.test('test'); // false - also relative URL

解释正则表达式

^(?:[a-z]+:)?//

^- 字符串的
(?:开头 - 未捕获组的开头
[a-z]+- 'a' 到 'z' 的任何字符 1 次或多次
:- 字符串(冒号字符)
)?- 未捕获组的结尾。组出现 0 或 1 次
//- 字符串(两个正斜杠字符)
'i'- 不区分大小写标志

于 2013-10-31T14:57:07.580 回答
39
var pat = /^https?:\/\//i;
if (pat.test(urlString))
{
    //do stuff
}

对于协议相对 url,使用这个正则表达式:

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

于 2012-05-21T14:27:00.213 回答
28

原始答案

一个非常快速且非常灵活的检查是:

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

这将识别绝对 URL,如果:

  • URL 在第一个字符之后的任何位置都包含“://” ,或者
  • URL 以“//”开头(相对于协议)

  • 没有正则表达式。
  • 没有 jQuery 或其他依赖项。
  • 没有使条件区分大小写的硬编码协议名称。
  • 没有字符串操作(例如 toLowerCase 或类似的)。
  • 仅检查“相对或绝对”但不进行任何其他健全性检查,可用于 Web URL 或任何内部协议。

更新 1(全功能示例)

这是一个返回给定 URL 的 true/false 的快速函数

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

在 ES6 中也一样:

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

更新 2(URL 参数内的 URL)

/redirect?target=http://example.org要以我建议使用以下代码的格式另外处理 URL :

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
}

简写形式和 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)

以下是一些测试用例:

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

更新 3(澄清相对 URL)

我看过一些关于无效输出的评论:

  • 解决方案返回 falselocalhost
  • 答案失败http:example.com

但是,这些 URL 确实是相对 URL。很容易测试:

  1. 在您的 localhost webroot 上创建一些文件夹,比如说a/b/c/
  2. 创建一个 index.html 文件并将以下链接放入其中:<a href="localhost">test</a>
  3. 在浏览器中打开索引页面:http://localhost/a/b/c/index.html并单击链接。您将以http://localhost/a/b/c/localhost结束(而不是http://localhost
  4. 将链接http:example.com放入 index.html 文件时也会发生同样的情况。您以http://localhost/a/b/c/example.com而不是http://example.com结束
于 2016-08-16T15:44:42.570 回答
20

根据您的需要,我认为确定这一点的更可靠方法是使用内置 URL 接口来构造几个 URL 对象并比较来源。

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

这允许浏览器为您解析和计算所有这些,而不必担心边缘情况的副作用。

于 2019-07-15T22:12:40.393 回答
18

使用正则表达式:

if (/^(?:[a-z]+:)?\/\//i.test(url))
于 2012-05-21T14:25:49.200 回答
12

更通用的符合 RFC 的 URI 方法:

(?:^[a-z][a-z0-9+\.-]*:|\/\/) 正则表达式解释

此处列出的其他解决方案对于以下链接将失败mailto:evan@nylas.com

RFC 3986方案定义为:

scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )

3.1。方案 https://www.rfc-editor.org/rfc/rfc3986#section-3.1

虽然根据第 4.2 节,相对协议的 url 在技术上是有效的,但 Paul Irish 却反过来认为这是一种反模式。见http://www.paulirish.com/2010/the-protocol-relative-url/

4.2. 相对参考 https://www.rfc-editor.org/rfc/rfc3986#section-4.2

如果您想要不使用相对协议 url 的正则表达式:

^[a-z][a-z0-9+\.-]*:

要查看其他类型的有效 uri 边缘情况的完整列表,请在此处查看列表:https ://en.wikipedia.org/wiki/URI_scheme

于 2015-08-13T15:00:20.020 回答
10

现在,当很多服务使用协议相对 URL(例如//cdn.example.com/libary.js)时,这种方法更安全:

var isAbsolute = new RegExp('^([a-z]+://|//)', 'i');

if (isAbsolute.test(urlString)) {
  // go crazy here
}
于 2013-10-30T19:23:22.193 回答
8

不要使用正则表达式等低级的东西。这些东西已经被很多其他人解决了。特别是边缘情况。

看看URI.js,它应该可以完成这项工作:http ://medialize.github.io/URI.js/docs.html#is

var uri = new URI("http://example.org/");
uri.is("absolute") === true;
于 2014-01-30T16:43:36.747 回答
5

您可以使用 try, catch 块来帮助解决此问题。您可以在每一步都使用URL界面,而不是使用正则表达式。

isExternalUrl (urlString) {
  try {
    const url = new URL(urlString) // THROW ON MISSING SCHEME

    // DOES THIS URL ORIGINATE FROM THIS WEBSITE?
    if (url.origin !== new URL(document.URL, document.baseURI).origin) {
      return true // IS EXTERNAL URL
    }
  } catch (_e) {
    // THROWS WHEN URL DOES NOT HAVE A SCHEME
    new URL(urlString, document.baseURL) // THROW AN EXCEPTION IF THE URL IS TRULY MALFORMED IN SOME WAY
  }

  return false
}
于 2020-08-12T10:34:46.377 回答
5

这是浏览器环境的一个非常强大的解决方案:

让浏览器处理一切。不需要一些复杂/容易出错的正则表达式。

const isAbsoluteUrl = (url) => {
  const link = document.createElement('a');
  link.href = url;
  return link.origin + link.pathname + link.search + link.hash === url;
};
于 2018-11-21T16:36:32.710 回答
4
var external = RegExp('^(https?:)?//');
if(external.test(el)){
    // do something
}

编辑:

使用下一个正则表达式,您甚至可以检查链接是指向同一个域还是指向外部域:

var external = RegExp('^((f|ht)tps?:)?//(?!' + location.host + ')');
if(external.test(el)){
    // do something
}
于 2012-05-21T14:29:44.593 回答
2
var adress = 'http://roflmao.com';
if (adress.substr(0,7) == 'http://' || adress.substr(0,8) == 'https://') {
    //
}
于 2012-05-21T14:27:58.977 回答
2

上述解决方案都没有解决redirect_url黑客进入的黑客攻击/\/example.com/\\/example.com. 这是我想出来确定我们的重定向 url 是否是相对的:

var isRelative = !redirectUrl.match(/(\:|\/\\*\/)/);  // Don't allow "//" (with optional "\"'s) or ":"
于 2018-11-29T21:45:16.657 回答
1

它不应该以斜杠或哈希开头,如果前面没有问号或哈希,它不应该包含双斜杠?我不会用一个正则表达式来测试它,匹配“没有双斜杠”会非常复杂。

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

会更容易,更清晰,恕我直言更快。

于 2012-05-14T19:19:15.733 回答
0

当超链接上发生单击事件时将调用以下函数,即“a”标签如果标签包含 url 将是相对的或包含相同的主机,那么新页面将被加载到相同的浏览器选项卡中,如果它包含不同的 url,则页面将加载在新的浏览器选项卡中

jQuery(document).ready(function() {
    $('a').click(function(){

        var a = this;
        var a_href = $(this).attr('href');
        var regex = new RegExp('^(?:[a-z]+:)?//', 'i');     

        if(a.host == location.host || regex.test(a_href) == false){
            a.target = '_self';
        }else{
            a.target = '_blank';
        }
    }); 
});
于 2015-10-16T15:44:48.210 回答
-1
var isExternalURL = url.toLowerCase().indexOf('http://') === 0 || url.toLowerCase().indexOf('https://') === 0 ;
于 2016-09-13T12:53:11.290 回答