相対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'属性をクエリすることです。これに関する問題は、サーバー要求を生成することです。避けたいもの。

だから私の質問は:IE6で相対URLから(サーバー要求なしで)完全修飾URLを取得する方法はありますか?


正規表現/文字列の簡単な修正をお勧めする前に、それはそれほど単純ではないことを保証します。基本要素+二重期間の相対URL +他の潜在的な変数のトンは本当にそれを地獄にします!

巨大な正規表現ソリューションを作成せずにそれを行う方法があるはずですか?


1
js-uriを使用して、相対URIを絶対URIに解決できます。
ガンボ

ガンボありがとう、私はこれがしなければならないと思います。もっと簡潔な解決策が欲しかったのですが、とにかくありがとう、このjs-uriクラスが存在することを知りませんでした!
ジェームズ

8
甘いハック!IE6は気にしないでください。時間を節約できました。あなたは揺れる。
トムハリソン

私はこれで動作しませんでした、私はただ「foo」を持っていて、「example.com/foo」が欲しいです
Jaime Hablutzel 2012年

js-uriライブラリは、元の投稿者が望んでいることを実行していないようです。
djsmith 2012

回答:


47

不思議ですね!ただし、DOMメソッドの代わりにinnerHTMLを使用すると、IEはそれを理解します。

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
Sebastien Lorber 2014

このアプローチは、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 2013

2
任意のベースURLをサポートする以外に、これは質問で提示されたソリューションとどの程度正確に異なりますか?IE 6で動作しますか?
ジョン

1
@AmadeusDrZaiusすべきではありませんが、必要に応じて可能です。Javascriptは、行の終わりに自動セミコロンを追加するだけで、次の行が無効なステートメントになることはありません。「、foo = 1」は構文エラーであるため、varステートメント全体がセミコロンの挿入なしで一括で評価されます。
ecmanaut 2014

2
@AndreasDietrichこれは、base_urlパラメーターに引数を渡さないためです。そのため、パラメーターはになりundefined、に文字列化され"undefined"ます。代わりに、空の文字列を渡す必要があります。それとも、あなたは第二のパラメータ、オプション、使用したい場合はour_base.href = base_url || ""代わりのour_base.href = base_url..を
オリオール

1
良い考えです、@ Oriol –両方のパラメーターを渡さない人々にとってより親しみやすいデフォルトの振る舞いをしない理由はありません。統合。
ecmanaut 2016

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で利用できますが、同様の名前の他のライブラリではありません
y3sh 2015

名前の付いたnpmパッケージがurijs github.com/medialize/URI.js#using-urijsに
Daniel Lizik 2016

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(または7、8)はサポートしていませんdocument.implementation.createHTMLDocument
Oriol

これは、Webアプリを使用して他のページをロードおよびスクレイプするときに使用しました。jQuery.loadからのコールバック$("#loadedHere").createElement("a").url="foo"で、空のURLが生成されたため、別のドキュメントを作成する必要がありました。
ericP 2017

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 2017

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に設定した場合でも、テストしたブラウザーがimagesrc属性を設定するとすぐにリソースをダウンロードすることです。

代わりに、bobinceのソリューションを試してみます。


0

url'/'で始まらない場合

現在のページのURLを取得し、最後の「/」以降のすべてを切り取ります。次に、相対URLを追加します。

それ以外の場合urlは「/」で始まります

現在のページのURLを取得し、単一の「/」の右側にあるすべてのものを切り取ります。次に、URLを追加します。

それ以外の場合urlは、#または?で始まります

現在のページのURLを取得し、単に追加します url


それがあなたのために働くことを願っています


2
URLが「//」で始まる可能性があることを忘れたため、スキームに依存します。//foo.com/bar/
Scott Wolchok 2010年

1
また、点線の相対../../構文を忘れました(この省略が重要かどうかは、出力が何に必要かによって異なります)
Hallvors 2012

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