【概要】
SpringでJSON形式の固定文言を返却するWeb APIを作成します。
作成したWeb APIをブラウザから非同期処理で呼び出し、JSONPの有効性を確認します。
確認するパターンとしては下記4通りで、一番右のWeb API呼び出し結果の列にはパターンごとの実行結果を記載しています。
パターンNo | 同一オリジンである | JSONPを使用する | Web API呼び出し結果 |
---|---|---|---|
1 | Yes | Yes | 正常 |
2 | Yes | No | 正常 |
3 | No | Yes | 正常 |
4 | No | No | エラー |
【環境】
Java11
Google Chrome
【構成イメージ】
ポート番号のみを変更したサーバを2台用意します。
サーバに用意されているWeb API(Javaソース)は、ほぼ同一です。
ブラウザには同一オリジンであるSame-Originサーバのhtmlを表示し、そのhtmlに用意されたボタンをクリックすることでWeb APIを呼び出します。
【コード】
GitHubにアップロードしてあります。
Javaソースは、JSON形式の固定文言を返却するWeb APIです。
htmlソースは、Web APIを呼び出すための画面です。
ボタンをクリックすることにより非同期処理でWeb APIを呼び出し、呼び出し結果をダイアログで表示します。
ソースコード一部抜粋
javaソースはWeb APIのメイン処理を抜粋しています。
public String execute(@RequestParam(required = false) String callback, HttpServletResponse response) {
// JSON形式の固定文言
String json = "{ \"name\": \"suzuki\", \"age\": \"30\" }";
// パターン4の回避用
// response.setHeader("Access-Control-Allow-Origin", "http://localhost:50001");
// JSONPを使用する場合
if (callback != null) {
// JSONP用
return callback + "(" + json + ")";
}
return json;
}
index.htmlはsameorigin-apiプロジェクトのみにあります。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<script>
function getJson(jsonUrl) {
$.ajax({
url: jsonUrl,
dataType: 'json'
}).done(function (json) {
alert(JSON.stringify(json));
}).fail(function () {
alert('getJson failed');
});
}
function getJsonp(jsonUrl) {
$.ajax({
url: jsonUrl,
dataType: 'jsonp',
jsonpCallback: 'test',
}).done(function (json) {
alert(JSON.stringify(json));
}).fail(function () {
alert('getJsonp failed');
});
}
</script>
</head>
<body>
<button onclick="getJsonp('http://localhost:50001/sameorigin/api?callback=test')">パターン1 Same-Origin かつ JSONP使用</button>
<br><br>
<button onclick="getJson('http://localhost:50001/sameorigin/api')">パターン2 Same-Origin かつ JSONP不使用</button>
<br><br>
<button onclick="getJsonp('http://localhost:50002/crossorigin/api?callback=test')">パターン3 Cross-Origin かつ JSONP使用</button>
<br><br>
<button onclick="getJson('http://localhost:50002/crossorigin/api')">パターン4 Cross-Origin かつ JSONP不使用</button>
</body>
</html>
【実行準備】
Eclipseにプロジェクトをmavenプロジェクトとしてインポートし、pom.xmlをインストール実行します。
その後、それぞれのプロジェクトをSpring Bootアプリケーションで起動し、以下のURLへアクセスします。
http://localhost:50001
【実行結果】
パターン1~4までのボタンをクリックした時の実行結果は下記通りとなります。
パターン1~3までの実行結果はいずれも同じです。
パターン1~3
Web API呼び出し結果は正常のため、JSON形式の固定文言が出力されます。
パターン4
Web API呼び出し結果はエラーのため、JSON形式の固定文言が出力されずエラーメッセージが出力されます。
エラーとなった原因は同一オリジンではないサイトに対して、JSONPを使用していないためです。
開発者ツールのコンソールタブを開くと下記エラーメッセージが出力されていることが確認できます。
ただ、エラーメッセージはJSONPが使われていませんという説明ではなく、レスポンスヘッダにAccess-Control-Allow-Originヘッダがありませんという説明になります。
CORSポリシーのエラー文を抜粋したのが下記文言です。
Access to XMLHttpRequest at 'http://localhost:50002/crossorigin/api' from origin 'http://localhost:50001'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
このエラー文で説明された通り、JavaソースにAccess-Control-Allow-Originヘッダを追加すればエラーが解消し、パターン1~3と同じ結果となります。
-// response.setHeader("Access-Control-Allow-Origin", "http://localhost:50001");
+ response.setHeader("Access-Control-Allow-Origin", "http://localhost:50001");