如何测试URL字符串是绝对的还是相对的?

Tru*_*an1 64 javascript string url jquery

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

if (urlString starts with http:// or https://)
 //do this
Run Code Online (Sandbox Code Playgroud)

Geo*_*Geo 147

快速

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

if (urlString.indexOf('http://') === 0 || urlString.indexOf('https://') === 0)
Run Code Online (Sandbox Code Playgroud)

普遍

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

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
Run Code Online (Sandbox Code Playgroud)

解释RegExp

^(?:[a-z]+:)?//
Run Code Online (Sandbox Code Playgroud)

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

  • `new RegExp('^(//|[az]+:)', 'i')` 应该适用于匹配 `mailto:`、`about:`、`tel:` 等,包括现有的测试用例。这里的想法是仍然提供协议相关的绝对 URL,同时扩展检测绝对 URL 的现有功能,而不需要检查双正斜杠 (`//`)。因此,`r.test('mailto:hi@example.com') === true`,`r.test('https:example.com') === true`,等等。 (5认同)
  • 是的,但我们不在这里检查域名,是吗?这仍然有效:`/ ^(?:[az] +:)?\ /\// i.test('https://www.ex-maple-123.com');` (3认同)

str*_*rah 30

var pat = /^https?:\/\//i;
if (pat.test(urlString))
{
    //do stuff
}
Run Code Online (Sandbox Code Playgroud)

对于协议相对URL,请使用此正则表达式:

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

  • 这回答了问题,但您可能还想考虑[protocol relative urls](http://www.paulirish.com/2010/the-protocol-relative-url/),它以`//`开头. (13认同)
  • 如果 url 包含“file://”怎么办?繁荣!悲剧。@Philipp 的回答更可靠。 (4认同)
  • 接受的答案是无效的,至少在 2019 年是这样。Chrome 很乐意接受 http:example.com。 (3认同)

SLa*_*aks 17

使用正则表达式:

if (/^(?:[a-z]+:)?\/\//i.test(url))
Run Code Online (Sandbox Code Playgroud)


Phi*_*ipp 16

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

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

如果出现以下情况,这将识别绝对URL:

  • URL 第一个字符后面的任何位置包含"://" ,或
  • URL以"//"开头(协议相对)

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

更新

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

function isUrlAbsolute(url) { 
    return (url.indexOf('://') > 0 || url.indexOf('//') === 0);
}
Run Code Online (Sandbox Code Playgroud)

在ES6中也是如此:

const isUrlAbsolute = (url) => (url.indexOf('://') > 0 || url.indexOf('//') === 0)
Run Code Online (Sandbox Code Playgroud)

更新2

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

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
}
Run Code Online (Sandbox Code Playgroud)

简短形式和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)
Run Code Online (Sandbox Code Playgroud)

以下是一些测试用例:

// 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
Run Code Online (Sandbox Code Playgroud)

  • 不.我只是追踪我的项目中的一个错误,发现它太功能了.该网页有一个像`/ redirect?target = http:// example.org`的网址 (3认同)
  • `isUrlAbsolute('redirect')` 给出 `false`,这是正确的,但 `isUrlAbsolute('redirect?target=http://example.org')` 给出 `true`,这是不正确的。我认为检查“://”是否位于“?”或“#”之后会很有用……是否有任何情况会与某些内容发生冲突? (3认同)

Bra*_*rad 12

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

new URL(document.baseURI).origin === new URL(urlToTest, document.baseURI).origin;
Run Code Online (Sandbox Code Playgroud)

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

  • 我对每一个基于正则表达式的答案都投了反对票,并对每一个使用“URL”等内置类的答案投了赞成票。这是正确的答案。谢谢! (4认同)

Jon*_*han 11

您可以使用 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
}
Run Code Online (Sandbox Code Playgroud)

  • 8年后,这是最好的答案 (2认同)

Eva*_*van 10

更符合Universal RFC标准的URI方法:

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

此处列出的其他解决方案将失败,如链接 mailto:evan@nylas.com

RFC 3986将Scheme定义为:

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

3.1.方案 https://tools.ietf.org/html/rfc3986#section-3.1

虽然协议相对网址在技术上是有效的,因为4.2节,保罗爱尔兰已经转回另一条路,并认为这是一种反模式.见http://www.paulirish.com/2010/the-protocol-relative-url/

4.2.相对参考 http://tools.ietf.org/html/rfc3986#section-4.2

如果您不喜欢没有协议相关网址的正则表达式:

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

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

  • 那个`^`应该走出小组吗?如上所述,它将在非起始位置匹配`//`(因此像`#//`这样的相对URL会匹配).此外,重要的是要指定此正则表达式应该不区分大小写,因此完整的定义看起来像`/ ^(?:[az] [az0-9 + .-]*:|| /\ /)/ i`. (3认同)

rgt*_*gtk 9

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

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

if (isAbsolute.test(urlString)) {
  // go crazy here
}
Run Code Online (Sandbox Code Playgroud)

  • 只需设置“ i”标志即可忽略大小写。答案已编辑。谢谢。 (2认同)

dav*_*ids 5

var external = RegExp('^(https?:)?//');
if(external.test(el)){
    // do something
}
Run Code Online (Sandbox Code Playgroud)

编辑:

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

var external = RegExp('^((f|ht)tps?:)?//(?!' + location.host + ')');
if(external.test(el)){
    // do something
}
Run Code Online (Sandbox Code Playgroud)


kop*_*por 5

不要使用诸如regexp等低级的东西。这些东西已经被很多其他人解决了。尤其是边缘情况。

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

var uri = new URI("http://example.org/");
uri.is("absolute") === true;
Run Code Online (Sandbox Code Playgroud)

  • 如果您需要进行很多操作,则很有用,但仅为此目的而使用JS库似乎有点过头了。 (4认同)

Eti*_*tin 5

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

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

const isAbsoluteUrl = (url) => {
  const link = document.createElement('a');
  link.href = url;
  return link.origin + link.pathname + link.search + link.hash === url;
};
Run Code Online (Sandbox Code Playgroud)