JSONPとは何かとjQueryが必要だった理由

JSONPはAjaxの裏技でした

結論から書きます。
JSONPは通信技術ではありません。
ブラウザのセキュリティ制限を回避するための「仕組み」です。

しかもAjax(XMLHttpRequest)ではありません。
実体はscriptタグの読み込みです。

この点を理解すると、なぜjQueryが必要だったのか、そしてなぜJSONPが消えていったのかが一気に見えてきます。

なぜそもそも回避が必要だったのか

ブラウザには同一オリジン制約(Same Origin Policy)があります。
簡単に言うと

  • 別ドメインのサーバへAjax通信できない

というルールです。

例えば

https://example.com

のページから

https://api.other.com

へXMLHttpRequestを送ると、ブラウザがブロックします。
これはバグではなく、ユーザーの情報を守るための仕様です。

つまり当時のWebでは
外部APIを呼び出せない
という問題がありました。

しかし実際には、天気APIや地図APIなど外部データを使いたい場面は多く存在します。
ここで考え出されたのがJSONPです。

JSONPの仕組み

ポイントは1つです。

scriptタグは別ドメインから読み込める。

HTMLを思い出してください。

<script src="https://cdn.example.com/lib.js"></script>

CDNのJavaScriptは普通に読み込めます。
ブラウザはこれを制限しません。

JSONPはこの仕様を利用します。

通常のAjax:

サーバ → JSONを返す

JSONP:

サーバ → JavaScriptを返す

つまりレスポンスはJSONではありません。
関数呼び出しコードです。

例を見ます。

サーバが返す内容:

callback({"name":"taro","age":20});

これはデータではなく、実行されるJavaScriptです。
scriptとして読み込まれるとブラウザがそのまま実行します。

実際の流れ

1. ページがscriptタグを生成
2. 外部サーバにリクエスト
3. サーバがJavaScriptを返す
4. ブラウザが実行
5. コールバック関数にデータが入る

つまり通信ではなく、コード実行です。

手書きJSONPの大変さ

jQueryなしでJSONPを書くとこうなります。

function callback(data){
  console.log(data);
}

var script = document.createElement("script");
script.src = "https://api.example.com/user?callback=callback";
document.body.appendChild(script);

問題点があります。

  • コールバック名管理
  • script削除
  • エラー検出不可
  • タイムアウト管理不可
  • 多重リクエスト困難

これを安全に書くのはかなり難しいです。

jQueryが必要だった理由

jQueryはJSONP処理を自動化しました。

$.ajax({
  url: "https://api.example.com/user",
  dataType: "jsonp",
  success: function(data){
    console.log(data);
  }
});

内部で次のことを行います。

  • 一意なコールバック関数生成
  • scriptタグ作成
  • 実行後の削除
  • タイムアウト処理
  • 複数同時通信の管理

つまりjQueryはJSONPの管理システムでした。

これが当時、外部APIを扱う事実上の標準手段になった理由です。

JSONPの危険性

JSONPは便利ですが、安全ではありません。

理由はシンプルです。
JavaScriptを実行しているからです。

サーバが次を返したらどうなるでしょうか。

alert(document.cookie);

そのまま実行されます。
つまりJSONPは外部サイトにコード実行権を渡しています。

これは現在のセキュリティ基準では非常に危険です。

さらに重要な制限があります。

  • GETしか使えない
  • HTTPステータスが分からない
  • 失敗を検知できない

通信ではないため、エラーを判断できません。

JSONPが消えた理由 ― CORS

現在はCORS(Cross-Origin Resource Sharing)があります。

サーバが許可ヘッダを返すことで、
XMLHttpRequestやfetchで外部ドメインへ通信できます。

つまり

  • JSONP → 回避策
  • CORS → 正式仕様

になりました。

fetchで普通に書けます。

fetch("https://api.example.com/user")
  .then(r=>r.json())
  .then(console.log);

これが可能になったことでJSONPの役割は終了しました。

まとめ

JSONPはAjax通信の一種ではありません。
scriptタグを利用したセキュリティ制限の回避手法です。

jQueryが必要だったのは、JSONPの実装が複雑で危険だったからです。
jQueryはその危険な仕組みを管理するための安全装置の役割を果たしていました。

そしてCORSの登場により、
回避策は不要になり、正規の通信が可能になりました。

JSONPは古い技術ですが、
Webがどのように制約を乗り越えて進化してきたかを象徴する仕組みと言えます。