クロスオリジンアクセス
ビットイメージの地図レイヤーに図法変換が必要な場合や、XMLHttpRequestやfetchなどでwebappのあるサイトと異なるドメインにあるウェブサービス(webapi)にアクセスする場合、クロスオリジンアクセス制限によるエラーが起きる場合があります。このエラーはWebApp側だけでは解決できず、サーバ側の設定を調整する必要があります。
目次 |
概要
SVGMapはハイパーレイヤリングアーキテクチャを持つため、ルートhtml文書で構成されるクライアントのSVGMapフレームワークウェブアプリは、異なるオリジンのサーバにアクセスすることが基本的に必要になります。これは一般的に「クロスオリジンリソース共有」と呼ばれる処理が行われる可能性があり、この時ウェブブラウザのネイティブな機能によるCORSのエラーが生じる可能性があることを意味します。
クロスオリジンアクセスのケースと、CORSのエラー発生の可能性を下表に示します。
クロスオリジンアクセスするコンテンツの種類 | コンテンツの処理 | CORSエラー発生の可能性 |
---|---|---|
ビットイメージ(タイルを含む) | 重ね合わせ | 発生しない |
ビットイメージ(タイルを含む) | 非線形図法変換を伴う重ね合わせ | 発生する可能性あり |
ビットイメージ(タイルを含む) | 地理空間情報処理等 | 発生する可能性あり |
ベクトルデータやjson等ビットイメージ以外のデータ | 重ね合わせ | 発生する可能性あり |
ベクトルデータやjson等ビットイメージ以外のデータ | 地理空間情報処理等 | 発生する可能性あり |
全ての種類のコンテンツ・データ | Cesium拡張を用いた表示 | 発生する可能性あり |
エラーの確認方法
ウェブブラウザでSVGMapのページを開き、開発ツールのコンソールもしくはネットワーク画面からエラーが確認できます。(blocked by CORS policyなどといったメッセージが出ます)
サーバ(サービス側での対処): CORSレスポンスヘッダを返すように設定する
- Access-Control-Allow-Origin *(もしくは指定オリジン)のレスポンスヘッダを返すようにサーバを設定します。
- 外部からのアクセスを想定し 整備されたサービスでは、この設定がされており(例:地理院地図やgitHubPagesのサイト) 下記プロキシの利用は不要です。
プロキシサービスを用意し これを経由させる
- node.jsによる実装
- phpによる実装
- php-cross-domain-proxy (svgmap.orgのfork)
- 単純なプロキシ実装例
プロキシ経由のクロスオリジンアクセスを容易にするためのSVGMap.jsの支援機能
プロキシ経由のクロスオリジンアクセスの対応を容易にするためのいくつかの機能がSVGMap.jsに備わっています。
SVGMap.jsがクロスオリジンアクセスを必要とするケースは主に3つあります。
- ビットイメージ(含タイル)データの図法変換
- ラスターGIS
- webAppレイヤーでの独自の通信
1.と2.はSVGMap.jsの管理下でクロスオリジンアクセスを行う必要があるもので、SVGMap.jsの初期化時にクロスオリジンアクセスのための設定(クロスオリジンアクセスのためのプロキシの設定)を行うAPIが用意されています。
これらのAPIを用いた初期化の例は次章で説明します。
WebApp Layerにおけるクロスオリジンアクセス
一方、3.は各レイヤーのwebApp(webApp Layer)が、レイヤーのコンテンツを生成するためのデータ(例えばjson形式の独自データ)を取得するときに(fetchやXMLHttpRequest等を使い)クロスオリジンアクセスするケースで、厳密にはSVGMap.jsが関与しない処理です。このようなクロスオリジンアクセスに対するケアは、基本的に個々のレイヤーwebAppの開発者が行う必要があります。
しかしプロキシ経由のアクセスを行う場合、先の1.2.のケース用に使用するプロキシを全レイヤー共通のプロキシとしても利用する場合が考えられ、この時にはSVGMap.jsの初期化で設定したプロキシを共通の関数で呼び出せる関数が用意されています。
getCORSURLの使用法は後の章で紹介します。
SVGMap.jsの初期化
<!doctype html> <html> ... <script src="corsProxy.js"></script> <!-- クロスオリジンアクセス用プロキシライブラリ(下記) --> <script src="SVGMapLv0.1_r17.js"></script> ... <script> var proxyPath = "{セットアップしたCORS AnywhereのURL}"; // CORS anywhere for svgmap.org / service.svgmap.org corsProxy.setService(proxyPath, null, true,false); svgMap.setProxyURLFactory(null,null,null, corsProxy.getURL,true); </script> ... </html>
corsProxy.js
初期化を容易に行うためのライブラリをご紹介します。gitHub
- corsProxy.setService(pxUrl , directURLls , useAnonProxy, requireEncoding)
- pxUrl : プロキシのURL
- directURLls : [プロキシを使用しないURLのリスト]
- useAnonProxy : anonymous属性を付与するかどうか
- requireEncoding : プロキシサービスに渡すURLをURLエンコードするかどうか
- corsProxy.getURL(プロキシに取得させるURL)
var corsProxy = (function(){ var proxyUrl=""; var anonProxy = false; var directURLlist = []; var noEncode=true; function setImageProxy( pxUrl , directURLls , useAnonProxy, requireEncoding){ if ( requireEncoding ){ noEncode = false; } proxyUrl = pxUrl; if ( directURLls ){ directURLlist = directURLls; } else { directURLlist = []; } if ( pxUrl.indexOf("http")==0){ var pxDomain = pxUrl.substring(0,pxUrl.indexOf("/",8)); directURLlist.push(pxDomain); } if ( useAnonProxy ){ anonProxy = true; } else { anonProxy = false; } } function isDirectURL(url){ // urlに、directURLlistが含まれていたら、true 含まれていなかったらfalse var ans = false; for ( var i = 0 ; i < directURLlist.length ; i++ ){ if ( url.indexOf(directURLlist[i])>=0){ ans = true; break; } } return ( ans ); } function getImageURL(imageUrl){ // ローカル(同一ドメイン)コンテンツもしくはそれと見做せる(directURLlistにあるもの)もの以外をproxy経由のURLに変換する // proxyの仕様は、 encodeURIComponent(imageUrl)でオリジナルのURLをエンコードしたものをURL末尾(もしくはクエリパート)につけたGETリクエストを受け付けるタイプ if ( proxyUrl && imageUrl.indexOf("http") == 0){ if (isDirectURL(imageUrl)){ // Do nothing (Direct Connection) } else { if ( noEncode ){ imageUrl = proxyUrl + (imageUrl); } else { imageUrl = proxyUrl + encodeURIComponent(imageUrl); } // console.log("via proxy url:",imageUrl); } } else { // Do nothing.. } return (imageUrl); } return { setService:setImageProxy, getURL:getImageURL, } })();
webAppレイヤーでのクロスオリジンアクセス
クロスオリジンアクセスのためのSVGMap.jsの初期化がなされた状態のルートHTML文書(SVGMapページ)に登録されている各レイヤーのwebAppsでは、getCORSURL APIを使用することができます。
このAPIは、アクセスしたいサービスのURLに対して、共通で準備されたクロスオリジンアクセス用サーバを経由したアクセスを可能にするURLが得られる機能で、たとえば以下のように利用します。
var dataResponse = await fetch( svgMap.getCORSURL( serviceURL ) );
一方、もしクロスオリジンアクセスの初期化をしていないルートHTML文書(SVGMapページ)では、各レイヤーのwebAppsが独自にクロスオリジンアクセスの解決を行う必要があります。例えば、クロスオリジンアクセス用のプロキシとしてhttps://[myproxy.mydomain.com]/proxy/
というプロキシが用意されており、?targetURL=serviceURL
というクエリパラメータでアクセス先のサービスにアクセスする場合は、以下のようになるでしょう。
var dataResponse = await fetch( "https://[myproxy.mydomain.com]/proxy/?targetURL=" + serviceURL );
非線形図法変換
メルカトル図法と正距円筒図法間の図法変換など、1次アフィン変換(matrix(a,b,c,d,e,f))で変換ができない座標変換が伴うもの