Help us understand the problem. What is going on with this article?

【Lumen】Lumen製APIに対してクロスドメインアクセスを行う(CORS)

More than 1 year has passed since last update.

異なるドメインからアクセスしようとするとエラーが返される

異なるドメインでアクセスしようとすると以下のようなエラーが出るのは周知のことかと思います。(クロスドメイン制約)

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に作成する。

CorsMiddleware.php
<?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.php
$app->middleware([
    App\Http\Middleware\CorsMiddleware::class
 ]);

これで、ヘッダーにAccess-Control-Allow-Originが追加されてクロスドメイン間でもアクセスを行うことができる。

もし本番と開発環境で切り分ける必要があるなら.envファイルに書いて読み込むようにしておけばいいんじゃないですかね。

.env.example
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にちゃんとアクセス先を記述する必要がある。

CorsMiddleware.php
'Access-Control-Allow-Origin'      => 'http://★★★★★★★★★★',

あとクレデンシャルが必要な場合はAccess-Control-Allow-Credentialstrueにしておくこと。

クレデンシャル・・・ユーザーの認証に用いられる情報の総称。ここではCookieやベーシック認証のID、パスをさす。

CorsMiddleware.php
'Access-Control-Allow-Credentials' => 'true',

また、JavaScriptからAjaxで通信する際にクレデンシャルが必要な場合はJavaScript側でオプション設定する必要があります。
JavaScript(ここではjQuery)側のオプション設定を載せておきます。

post.js
        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に関して参考させていただいたサイト

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away