상대 URL에서 절대 URL 가져 오기. (IE6 문제)


80

현재 상대 URL을 절대 URL로 '변환'하기 위해 다음 함수를 사용하고 있습니다.

function qualifyURL(url) {
    var a = document.createElement('a');
    a.href = url;
    return a.href;
}

이것은 대부분의 브라우저에서 잘 작동하지만 IE6는 여전히 상대 URL을 반환하도록 고집합니다! getAttribute ( 'href')를 사용하면 동일합니다.

IE6에서 정규화 된 URL을 얻을 수 있었던 유일한 방법은 img 요소를 만들고 'src'속성을 쿼리하는 것입니다. 문제는 서버 요청을 생성한다는 것입니다. 피하고 싶은 것.

그래서 내 질문은 : (서버 요청없이) 상대 URL에서 IE6에서 정규화 된 URL을 얻는 방법이 있습니까?


빠른 정규식 / 문자열 수정을 권장하기 전에 그렇게 간단하지 않다고 확신합니다. 기본 요소 + 이중 기간 상대 URL + 수많은 다른 잠재적 변수가 정말 지옥을 만듭니다!

거대한 정규식 솔루션을 만들지 않고도 할 수있는 방법이 있어야합니다.


1
js-uri 를 사용 하여 상대 URI를 절대 URI로 확인할 수 있습니다.
Gumbo

Gumbo 고마워요. 그래야 할 것 같아요. 좀 더 간결한 해결책을 원했지만 어쨌든 감사합니다.이 js-uri 클래스가 존재한다는 것을 결코 몰랐습니다!
James

8
달콤한 해킹! IE6는 신경 쓰지 마세요. 시간을 절약했습니다. 당신은 흔들립니다.
Tom Harrison

나는 내가 그냥 "foo는"이,이 작업 내가 "원하는 도착하지 않았다 example.com/foo을 "
제이미 Hablutzel에게

js-uri 라이브러리는 원래 포스터가 원하는대로 작동하지 않는 것 같습니다.
djsmith dec.

답변:


47

얼마나 이상해! 그러나 IE는 DOM 메서드 대신 innerHTML을 사용할 때이를 이해합니다.

function escapeHTML(s) {
    return s.split('&').join('&amp;').split('<').join('&lt;').split('"').join('&quot;');
}
function qualifyURL(url) {
    var el= document.createElement('div');
    el.innerHTML= '<a href="'+escapeHTML(url)+'">x</a>';
    return el.firstChild.href;
}

조금 못 생겼지 만 스스로하는 것보다 더 간결합니다.


: 나는 탈출 코드를 필요로하지 않는 블로그에이 유사한 솔루션을 찾을 stackoverflow.com/a/22918332/82609
세바스티앙 Lorber

이 접근 방식은 HTML 사양 에 따라 null (U + 0000)을 (U + FFFD)로 대체합니다 .
Oriol

26

브라우저가 <base> 태그를 올바르게 구현하는 한 브라우저는 다음을 수행합니다.

function resolve(url, base_url) {
  var doc      = document
    , old_base = doc.getElementsByTagName('base')[0]
    , old_href = old_base && old_base.href
    , doc_head = doc.head || doc.getElementsByTagName('head')[0]
    , our_base = old_base || doc_head.appendChild(doc.createElement('base'))
    , resolver = doc.createElement('a')
    , resolved_url
    ;
  our_base.href = base_url || '';
  resolver.href = url;
  resolved_url  = resolver.href; // browser magic at work here

  if (old_base) old_base.href = old_href;
  else doc_head.removeChild(our_base);
  return resolved_url;
}

실험 할 수있는 jsfiddle은 다음과 같습니다. http://jsfiddle.net/ecmanaut/RHdnZ/


파티까지 3 년 늦었 기 때문에 마케팅이나 많은 사람들이 문제를 갖고 코드 보수적이고 정확한 솔루션을 원하지 않고 정상에 오르려면 시간이 걸릴 것입니다.
ecmanaut

2
임의의 기본 URL을 지원하는 것 외에 질문에 제시된 솔루션과 정확히 어떻게 다릅니 까? IE 6에서 작동합니까?
John

1
@AmadeusDrZaius 그렇게해서는 안되지만 원하는 경우 가능합니다. 자바 스크립트는 자동 세미콜론을 줄 끝에 추가하기 만하면 다음 줄이 유효하지 않은 문이되지 않습니다. ", foo = 1"은 구문 오류이므로 세미콜론 삽입없이 전체 var 문이 대량으로 평가됩니다.
ecmanaut

2
@AndreasDietrich 당신이 모든 인수를 전달하지 않기 때문에 그건 base_url이 될 수 있도록, 매개 변수 undefined및로도 캐릭터 라인입니다 "undefined". 대신 빈 문자열을 전달해야합니다. 또는 두 번째 매개 변수를 선택적으로 만들려면 .. our_base.href = base_url || ""대신 사용하십시오 our_base.href = base_url.
Oriol

1
좋은 생각, @Oriol – 두 매개 변수를 모두 전달하지 않는 사람들에게 더 친숙한 기본 동작을하지 않을 이유는 없습니다. 통합.
ecmanaut

16

요소를 복제하기 만하면 IE6에서 작동하도록 만들 수 있습니다.

function qualifyURL(url) {
    var a = document.createElement('a');
    a.href = url;
    return a.cloneNode(false).href;
}

(IE6 및 IE5.5 모드에서 IETester를 사용하여 테스트)


10

블로그 에서 찾았습니다 @bobince 솔루션과 같은 또 다른 방법을 .

function canonicalize(url) {
    var div = document.createElement('div');
    div.innerHTML = "<a></a>";
    div.firstChild.href = url; // Ensures that the href is properly escaped
    div.innerHTML = div.innerHTML; // Run the current innerHTML back through the parser
    return div.firstChild.href;
}

나는 그것이 큰 문제가 아니라 조금 더 우아하다는 것을 알았습니다.


7

URI.js 가 문제를 해결하는 것 같습니다.

URI("../foobar.html").absoluteTo("http://example.org/hello/world.html").toString()

http://medialize.github.io/URI.js/docs.html#absoluteto 참조

IE6에서는 테스트되지 않았지만 일반적인 문제를 검색하는 다른 사용자에게 도움이 될 수 있습니다.


1
사물의 노드 측 (크롤링 등)에서 올바른 라이브러리 npm install URIjs
는를

이름이 npm 패키지가 urijs github.com/medialize/URI.js#using-urijs로
Daniel Lizik

7

나는 실제로 원본 문서를 수정할 필요가 없지만 (일시적으로도 아님) 브라우저의 내장 URL 파싱 등을 사용하는 접근 방식을 원했습니다. 또한 내 자신의 기반을 제공 할 수 있기를 원했습니다 (예 : ecmanaught의 답변). 다소 간단하지만 createHTMLDocument를 사용합니다 (좀 더 호환되도록 createDocument로 대체 할 수 있음).

function absolutize(base, url) {
    d = document.implementation.createHTMLDocument();
    b = d.createElement('base');
    d.head.appendChild(b);
    a = d.createElement('a');
    d.body.appendChild(a);
    b.href = base;
    a.href = url;
    return a.href;
}

http://jsfiddle.net/5u6j403k/


1
내가 뭔가를 놓치고 있는지 확실하지 않지만 IE6 (nor 7, 8)은 지원하지 않습니다document.implementation.createHTMLDocument
Oriol

웹 앱을 사용하여 다른 페이지를로드하고 스크래핑 할 때 이것을 사용했습니다. jQuery.load의 콜백에서 $("#loadedHere").createElement("a").url="foo"빈 URL이 생성되어 별도의 문서를 만들어야했습니다.
ericP

5

이 솔루션은 모든 브라우저에서 작동합니다.

/**
 * Given a filename for a static resource, returns the resource's absolute
 * URL. Supports file paths with or without origin/protocol.
 */
function toAbsoluteURL (url) {
  // Handle absolute URLs (with protocol-relative prefix)
  // Example: //domain.com/file.png
  if (url.search(/^\/\//) != -1) {
    return window.location.protocol + url
  }

  // Handle absolute URLs (with explicit origin)
  // Example: http://domain.com/file.png
  if (url.search(/:\/\//) != -1) {
    return url
  }

  // Handle absolute URLs (without explicit origin)
  // Example: /file.png
  if (url.search(/^\//) != -1) {
    return window.location.origin + url
  }

  // Handle relative URLs
  // Example: file.png
  var base = window.location.href.match(/(.*\/)/)[0]
  return base + url

그러나 "../file.png"와 같이 ".."가 포함 된 상대 URL은 지원하지 않습니다.


이것은 몇 가지 문제가 있습니다. 예를 들어, base가 windows와 동일하다고 가정하고 url에 url param이 있으면 이것이 작동하지 않는다고 생각합니다. 말하십시오 /img/profile.php?url=https://google.com/logo.svg.
Teodors

3

이것은 기본 상대 URL을 확인하는 데 사용하는 기능입니다.

function resolveRelative(path, base) {
    // Absolute URL
    if (path.match(/^[a-z]*:\/\//)) {
      return path;
    }
    // Protocol relative URL
    if (path.indexOf("//") === 0) {
      return base.replace(/\/\/.*/, path)
    }
    // Upper directory
    if (path.indexOf("../") === 0) {
        return resolveRelative(path.slice(3), base.replace(/\/[^\/]*$/, ''));
    }
    // Relative to the root
    if (path.indexOf('/') === 0) {
        var match = base.match(/(\w*:\/\/)?[^\/]*\//) || [base];
        return match[0] + path.slice(1);
    }
    //relative to the current directory
    return base.replace(/\/[^\/]*$/, "") + '/' + path.replace(/^\.\//, '');
}

jsfiddle에서 테스트하십시오. https://jsfiddle.net/n11rg255/

브라우저와 node.js 또는 기타 환경에서 모두 작동합니다.


2

앵커 대신 이미지 요소 사용을 제안하는이 블로그 게시물을 찾았습니다.

http://james.padolsey.com/javascript/getting-a-fully-qualified-url/

이는 IE6에서도 URL을 안정적으로 확장하는 데 효과적입니다. 그러나 문제는 내가 테스트 한 브라우저가 다음 줄에서 src를 null로 설정하더라도 이미지 src 속성을 설정하면 즉시 리소스를 다운로드한다는 것입니다.

대신 bobince의 솔루션을 사용하겠습니다.


0

만약 url'/'로 시작하지 않는

현재 페이지의 URL을 가져 와서 마지막 '/'이후의 모든 것을 잘라냅니다. 그런 다음 상대 URL을 추가하십시오.

url'/'로 시작하는 경우

현재 페이지의 URL을 가져 와서 하나의 '/'오른쪽에있는 모든 것을 잘라냅니다. 그런 다음 URL을 추가하십시오.

그렇지 않으면 url# 또는?

현재 페이지의 URL을 가져 와서 간단히 추가 url


그것이 당신을 위해 일하기를 바랍니다


2
URL이 "//"로 시작할 수 있다는 사실을 잊었 기 때문에 스키마에 상대적입니다. //foo.com/bar/
Scott Wolchok 2010 년

1
또한 점으로 구분 된 상대 ../../ 구문을 잊어 버렸습니다 (이 생략이
중요한지

-1

브라우저에서 실행되면 이런 종류의 저에게 효과적입니다 ..

  function resolveURL(url, base){
    if(/^https?:/.test(url))return url; // url is absolute
    // let's try a simple hack..
    var basea=document.createElement('a'), urla=document.createElement('a');
    basea.href=base, urla.href=url;
    urla.protocol=basea.protocol;// "inherit" the base's protocol and hostname
    if(!/^\/\//.test(url))urla.hostname=basea.hostname; //..hostname only if url is not protocol-relative  though
    if( /^\//.test(url) )return urla.href; // url starts with /, we're done
    var urlparts=url.split(/\//); // create arrays for the url and base directory paths
    var baseparts=basea.pathname.split(/\//); 
    if( ! /\/$/.test(base) )baseparts.pop(); // if base has a file name after last /, pop it off
    while( urlparts[0]=='..' ){baseparts.pop();urlparts.shift();} // remove .. parts from url and corresponding directory levels from base
    urla.pathname=baseparts.join('/')+'/'+urlparts.join('/');
    return urla.href;
  }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.