異なるドメインからアクセスしようとするとエラーが返される
異なるドメインでアクセスしようとすると以下のようなエラーが出るのは周知のことかと思います。(クロスドメイン制約)
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://★★★★★★★★★★' is therefore not allowed access.
クロスドメインアクセスを行う場合はCORS(Cross-Origin Resource Sharing)の仕組みを使用する必要がある
LumenでCORSを使用する
以下のファイルを\app\Http\Middleware
に作成する。
<?php
namespace App\Http\Middleware;
use Closure;
class CorsMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
// TODO:Access-Control-Allow-Originを適切に指定する必要がある
$headers = [
'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Methods' => 'POST, GET, OPTIONS', // TODO:この部分も適切に設定する必要がある
'Access-Control-Allow-Credentials' => 'true',
'Access-Control-Max-Age' => '86400',
'Access-Control-Allow-Headers' => 'Content-Type, Authorization, X-Requested-With'
];
// preflightリクエスト用
if ($request->isMethod('OPTIONS'))
{
return response()->json('{"method":"OPTIONS"}', 200, $headers);
}
$response = $next($request);
foreach($headers as $key => $value)
{
$response->header($key, $value);
}
return $response;
}
}
そして、\bootstrap\app.php
に以下を追加する。
$app->middleware([
App\Http\Middleware\CorsMiddleware::class
]);
これで、ヘッダーにAccess-Control-Allow-Origin
が追加されてクロスドメイン間でもアクセスを行うことができる。
もし本番と開発環境で切り分ける必要があるなら.env
ファイルに書いて読み込むようにしておけばいいんじゃないですかね。
ACCESS_CONTROL_ALLOW_ORIGIN=*
ちなみにpreflightリクエストとは目的の通信をする前に事前に安全かどうかを確かめるリクエストのことをさします。
「プリフライト」リクエストは始めに OPTIONS メソッドによるリクエストを他のドメインにあるリソースに向けて送り、実際のリクエストを送信しても安全かどうかを確かめます。サイト間リクエストはユーザーデータに影響を与える可能性があるため、このようにプリフライトを行います。
引用:オリジン間リソース共有 (CORS) - HTTP | MDN
Basic認証をかけているサーバーにあるAPIに対してアクセスをする場合
Access-Control-Allow-Origin
にワイルドカード*
を指定してると以下のようなエラーが出る。
The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
Origin 'http://★★★★★★★★★★' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
ようはちゃんと指定して書けといわれてるのでAccess-Control-Allow-Origin
にちゃんとアクセス先を記述する必要がある。
'Access-Control-Allow-Origin' => 'http://★★★★★★★★★★',
あとクレデンシャルが必要な場合はAccess-Control-Allow-Credentials
もtrue
にしておくこと。
クレデンシャル・・・ユーザーの認証に用いられる情報の総称。ここではCookieやベーシック認証のID、パスをさす。
'Access-Control-Allow-Credentials' => 'true',
また、JavaScriptからAjaxで通信する際にクレデンシャルが必要な場合はJavaScript側でオプション設定する必要があります。
JavaScript(ここではjQuery)側のオプション設定を載せておきます。
function sendPostToApiByAjax()
{
$.ajax({
type: "POST",
url: "http://★★★★★★★★★★",
// username: "*****", // Basic認証用ユーザー名
// password: "*****", // Basic認証用パスワード
data: {
name : 'ajaxAPI' // リクエストパラメータ
},
xhrFields: {
withCredentials: true // クレデンシャル送るよオプション
},
}).done(function(data) {
console.log('Successful communication with API!');
}).fail(function(data) {
console.log('Ajax fail (communication error)');
});
}
おわり
- CORSむずかしい
- Laravelはbarryvdh/laravel-corsを入れたらよさげ(Lumenも対応してるみたいですがうまくいかなかった・・・)
参考
以下CORSに関して参考させていただいたサイト