2017年以前の旧ブログ

BLOG2017

jquery.xdomainajax.jsが動かない

OB・OG Other Blog

どうも、バンチです。
困ったときの技術ネタ
エンジニアっぽい記事、もっと増やさないとね。

Ajaxって?

Ajaxという技術があります。
詳しくはリンク先(Wikipedia)参照していただくとして、端的に言えばかっこいいサイトを作るために使われるものです。

Webページって基本的にページ単位で画面は独立していますよね。
ページとページはリンクでつながっているだけで、それぞれ開いたら上から下まで全部が書き換わります。
Ajaxは特定のページを表示したまま、裏側でサーバーと通信をして別の情報をとってくる仕組みです。
これができると何がうれしいかは実例みたほうが早いです。

たとえば Google検索

検索窓に入力をしていくと

google
こんな感じで候補がリアルタイムに出てきます。
場合によっては検索結果もリアルタイムで変わります。
このとき、いちいち画面が一回真っ白になってもう一回表示される、とかなったら使いづらくて仕方がありません。
そうならないように、裏でGoogleのサーバーと通信して表示する内容をとってきているのです。

クロスドメイン制約

Ajaxって便利そうですよね。
もう全部それでデータとってきたらいいんじゃない?って思いますよね。
でもそれはダメなんです。

Ajaxでどこからデータをとっているかは見ている人にはまずわかりません。
仮に悪意ある人がいて、危険なコンテンツをとりにいくようなことがあってもわからないため、ブラウザは基本的には同じドメインのデータしか取らないようにしています。

このドメインまたがった通信の制限をクロスドメイン制約といいます。

ちなみに・・・もっと細かいルールもありますし、最近のブラウザと特定の設定がされたサーバーであればクロスドメインでも通信できます。
が省略。

じゃあ、他のサーバーからデータをとりたいときは・・・?

jquery.xdomainajax.js

解決方法はいろいろあります。
phpを使ったり、jsonpを使ったり・・・
でもそれらが使えないこともそこそこあります。

そこで便利なのがjquery.xdomainajax.jsというjqueryライブラリ。

Ajax通信の処理を拡張して、クロスドメインでも通信できるようにしてくれる便利アイテムです。

でもね・・・これが突然使えなくなったのです。

原因は"YQLのサービス停止"です。
jquery.xdomainajax.jsは内部でこのサービスを利用して、他のドメインのデータを取得していたので、そのサービスが停止したことで動かなくなってしまったのです。

解決方法

というわけで、とりあえずの解決法王を紹介しておきます。
上ではYQLがサービス停止と書きましたが、正しくはYQLの中の「特定のページの内容を検索・取得できるサービス」が停止しただけです。
他のサービスは動作しているため、有志作成の似たサービスに切り替える方法をとります。

対策はxdomainajax.jsの中身を直接書き換えます。
ソース公開でもいいのですが、責任とか・・・いろいろ・・・
なので手順を紹介します。

1.使用するYQLのクエリーを変更

//query = 'select * from html where url="{URL}" and xpath="*"';
// ↑これを↓
query = 'select * from htmlstring where url="{URL}" and xpath="*"';

2.YQLに引き渡すパラメータを変更
※上記クエリーを使用できるようにするため

o.data = {
    q: query.replace(
        '{URL}',
        url + (o.data ?
            (/\?/.test(url) ? '&' : '?') + jQuery.param(o.data)
        : '')
    ),
    format: 'xml',
    // ↓を追加
    diagnostics: true,
    env: 'store://datatables.org/alltableswithkeys',
};

3.YQLの実行結果が若干異なるため、加工する処理を追加

return function(data) {
    if (_success) {
        var text = $((data.results[0] || '')
                // YQL screws with <script>s
                // Get rid of them
                .replace(/<script[^>]+?\/>|<script(.|\s)*?\/script>/gi, '')).text();
        // Fake XHR callback.
        _success.call(this, {
            responseText: text
        }, 'success');
    }
};

以上です。
ライブラリの使い方は変わらないため。呼出元の処理には手を入れる必要はありません。

一時的な対応ではありますが。もしお困りの方がいらっしゃれば試してみて下さい。