AJAX ProxyでWebサービスマッシュアップ

by Shinichi Tomita on 8月 2, 2007 at 04:13 午後

最近Salesforceプラットフォームに加わった機能である「AJAX Proxy」は、Salesforce上でのマッシュアップアプリケーションの可能性を広げるという点で大変有効な新機能です。

AJAX Proxyより以前のSalesforceでのマッシュアップは、Salesforce外部で提供されているXML Webサービスを統合しようとするとき、そのままではSalesforceからWebサービスを呼び出すことができませんでした。

これは、よく知られているWebブラウザのセキュリティモデルに起因しています。大半のWebブラウザでは、提供されているWebページと異なるドメインで提供されているWebサイトへのXMLHttpRequestの呼び出しができないようなセキュリティ設定になっています(同一生成元ポリシー: Same Origin Policy)。

このブラウザの制約を回避するため、一般的なAJAX Webアプリケーションではプロキシサービスをサーバ側に配置して、ドメインをまたがったリクエストを代理でおこなうような仕組み(クロスドメインプロキシ: Cross-Domain Proxy)によって複数サービス間のマッシュアップを行います。

Crossdomainproxy

今回ご紹介するAJAX Proxyもこのクロスドメインプロキシと同じデザインパターンなのですが、Salesforceがプラットフォームとしてこの機能を実装しているというところに特徴があります。つまりSalesforceの開発者は、プロキシを行うためのサーバサイドプログラムの配置についてまったく気にする必要はありません。

これにより、マッシュアップアプリケーションサービスを作るのにわざわざサーバ環境を調達する必要はなくなりました。必要なのはHTMLとJavaScriptのコードだけで、世の中に既に数多く存在しているWebサービスをマッシュアップするApexアプリケーションを作成することができます。

事前設定

AJAX Proxyを使う前に、管理者はあらかじめプロキシ経由で呼び出す予定のWebサービスを登録しておく必要があります。これはAJAX Proxy経由で勝手なWebサイトに接続してしまうことを防ぐためです。具体的にはSalesforceの設定画面でリモートサイトの設定を事前に行うことになります。

Salesforceに管理ユーザでログインした後、「設定」メニューから「管理者設定>セキュリティのコントロール>リモートプロキシの設定」を開き、「新規リモートサイト」のボタンをクリックします。入力フォームに対して下図のように入力してリモートサイトを設定します。なおリモートサイトのURLは呼び出し対象のWebサービスURLのルートURLを設定します。

Remotesite

外部Webサービスの呼び出し

AJAX Proxy は Salesforce のJavaScript用APIツールキットであるAJAX Toolkitから利用します。以下にホットペッパーのグルメサーチAPIを例に、AJAX Proxyを経由した外部Webサービス呼び出しのコード例を記します

sforce.connection.remoteFunction({
  url : 'http://api.hotpepper.jp/GourmetSearch/V110/?key=guest&Latitude=35.660818&Longitude=139.775426&Range=3',
  method : 'GET',
  mimeType : 'text/xml',
  onSuccess : handleResult,
  onFailure : handleError
})

remoteFunctionメソッドには、urlとしてWebサービス呼び出しを行うURLの値、methodとしてWebサービスのHTTPリクエストメソッドを、mimeTypeに結果レスポンスのMIME形式を指定します。結果レスポンスがXML形式で返却される場合には、mimeTypetext/xmlを指定しておくと、XMLパースされたDOM形式で結果を取得できます。

onSuccess および onFailureにはそれぞれリクエストの成功時および失敗時にコールバックされる関数を指定します。以下のようなコールバック関数を定義しておくことで、Webサービスリクエストの結果を処理することができます。

/**
* ホットペッパーグルメサーチAPIの検索結果から得られた店名をリストする
* レスポンスのXMLメッセージの形式については以下のURLを参照
* http://api.hotpepper.jp/reference.html
*/
function handleResult(doc) {
  var shops = doc.getElementsByTagName('Shop');
  var html = '<ul>';
  for (var i=0; i<shops.length; i++) {
    html += '<li>';
    html += shops[i].getElementsByTagName('ShopName')[0].firstChild.nodeValue;
    html += '</li>';
  }
  html += '</ul>';
  document.getElementById('output').innerHTML = html;
}

AJAX Proxyがプロキシ可能なHTTPリクエストは、GETメソッドだけでなくPOSTメソッドも可能です。たとえば以下のコードのようにXML-RPCを利用してブログに記事をポストすることもできます。

// MovableType XML-RPC仕様に沿ったメッセージ形式
var xmlMessage =
  '<?xml version="1.0"?>' +
  '<methodCall>' +
  '  <methodName>...</methodName>' +
  '  <params>..</params>' +
  '</methodCall>';

sforce.connection.remoteFunction({
  url : 'http://blog.drecom.jp/api/xmlrpc',
  method : 'POST',
  mimeType : 'text/xml',
  requestHeaders : {
    'Content-Type' : 'text/xml'
  },
  requestData : xmlMessage,
  onSuccess : handleResult,
  onFailure : handleError
})

制約事項と回避手段

実はAJAX Proxyには、プロキシ経由で呼び出すWebサービスが AJAX Proxy を呼び出しているページ(Sコントロール)と同じネットワークプロトコルで提供されていなければならない、という制約があります。これはつまり、HTTPSで提供されているWebサービスにリクエストするときはSコントロールもHTTPSで表示されている必要があり、逆にHTTPで提供されているWebサービスはSコントロール自体もHTTPで表示されている必要がある、ということです。プロトコルが一致していないと「Endpoint protocol(http/https) mismatch」というエラーが発生します。

これはもともと通信路におけるデータセキュリティの一貫性を損なわないために導入された制約なのですが、簡単なWebサービスのマッシュアップ用途には些かやり過ぎな感じがしないでもありません。残念ながら現時点ではマッシュアップの際にはこの制約を念頭においておく必要があります。

たとえば上の例でのホットペッパーAPIはHTTPで提供されているWebサービスであるため、Sコントロールの表示もHTTPにそろえる必要があります。Salesforceは通常HTTPSでアプリケーション画面を表示しますが、HTTP経由でも表示することができます(ただし管理者がセキュリティ設定によってHTTPを無効化している場合もあります)。以下のJavaScriptコードをSコントロールの先頭に記述しておくことで、常にHTTP経由でページを表示するようになるため、AJAX Proxyのプロトコルに対する制約を回避することができます。

if (location.href.indexOf('https')==0) {
  location.href = location.href.replace(/^https/, 'http');
}
追記 2007/12/08

Winter '08よりリモートサイト設定が変更され、オプションとしてHTTPの通信を許すことが出来るようになったため、上記のような回避策は必要なくなりました。

トラックバック

このページのトラックバックURL: http://www.typepad.jp/t/trackback/7240/10076641

このページへのトラックバック一覧 AJAX ProxyでWebサービスマッシュアップ:

コメントを投稿

コメントは記事の投稿者が承認するまで表示されません。