CORS対応のまとめ
当サイトの閲覧数で意外と多いのが、CORS関連のページです。
私もFlutter Webアプリを開発していて、最初にXMLHttpRequest errorに出会った時には意味が分からず解決にずいぶん苦労しました。
結論としてサーバアプリ側での対応が必要になりますが、その対応方法についてまとめておきたいと思います。
CORSの仕組みそのものは別のサイトを参照してください。
CORSとは
CORS(Cross-Origin Resource Sharing)は、ウェブサイトが異なるOrigin(プロトコル、ドメイン、ポート)からデータを取得する際のセキュリティに関する仕組みです。
ウェブサイトは、別のサイトからデータを取得したり、ファイルを読み込んだりすることがあります。しかし、セキュリティのために、許可されていないサイトからのデータ取得を防ぐ必要があります。そのため、ブラウザは異なるOrigin間のアクセスを基本的にブロックします。
CORSは、ウェブサイトが他の場所からデータを取得する際に、そのデータ提供元(APIサーバなど)が許可したサイトだけにアクセスを許可するルールを指定します。
Webアプリケーションの場合、リクエスト元の確認を行うのは、Webブラウザです。また許可をするのはサーバです。そのため、Flutterのアプリ内でCORSの処理をする必要はありません。
以下は、Webアプリから呼び出すAPIサーバを開発する際のサーバ側の対応について、プラットフォームごとに説明します。
対応1 Flaskの場合
VPS等でサーバをたて、Flaskで開発した場合には、以下のようにします。
ライブラリをインストールします。
$ pip install flask_cors
既存のFlaskコードに以下を追加します。
from flask_cors import CORS
app = Flask(__name__)
ーー 以下を追加 ーー
CORS(
app,
supports_credentials=True, // cookieを使う場合に設定。使わない場合は削除
origins=["https://****.***/"] // アクセスを許可するオリジンを指定。すべてのアクセスを許可する場合は削除
)
flask-corsの公式ドキュメントは以下にあります。
対応2 AWS Lambda Chaliceの場合
ChaliceのCORS対応については、公式のドキュメントに詳細に記載されています。
CORS¶
class CORSConfig(allow_origin='*', allow_headers=None, expose_headers=None, max_age=None, allow_credentials=None)¶
CORS configuration to attach to a route, or globally on
app.api.cors
.from chalice import CORSConfig cors_config = CORSConfig( allow_origin='https://foo.example.com', allow_headers=['X-Special-Header'], max_age=600, expose_headers=['X-Special-Header'], allow_credentials=True ) @app.route('/custom_cors', methods=['GET'], cors=cors_config) def supports_custom_cors(): return {'cors': True}
New in version 0.8.1.allow_origin¶
The value of the
Access-Control-Allow-Origin
to send in the response. Keep in mind that even though theAccess-Control-Allow-Origin
header can be set to a string that is a space separated list of origins, this behavior does not work on all clients that implement CORS. You should only supply a single origin to theCORSConfig
object. If you need to supply multiple origins you will need to define a custom handler for it that acceptsOPTIONS
requests and matches theOrigin
header against a whitelist of origins. If the match is successful then return just theirOrigin
back to them in theAccess-Control-Allow-Origin
header.allow_headers¶The list of additional allowed headers. This list is added to list of built in allowed headers:
Content-Type
,X-Amz-Date
,Authorization
,X-Api-Key
,X-Amz-Security-Token
.expose_headers¶A list of values to return for the
Access-Control-Expose-Headers
:max_age¶The value for the
Access-Control-Max-Age
allow_credentials¶A boolean value that sets the value of
https://aws.github.io/chalice/api.html?#corsAccess-Control-Allow-Credentials
.
上記引用コードにあるように、cors_configを設定し、@app.routeの引数に”cors=cors_config"を加えることで、対応できます。
対応3 Google Cloud Functionsの場合
Google Cloud Functionsの場合も公式のドキュメントにサンプルが掲載されています。
import functions_framework
@functions_framework.http
def cors_enabled_function(request):
# For more information about CORS and CORS preflight requests, see:
# https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
# Set CORS headers for the preflight request
if request.method == "OPTIONS":
# Allows GET requests from any origin with the Content-Type
# header and caches preflight response for an 3600s
headers = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET",
"Access-Control-Allow-Headers": "Content-Type",
"Access-Control-Max-Age": "3600",
}
return ("", 204, headers)
# Set CORS headers for the main request
headers = {"Access-Control-Allow-Origin": "*"}
return ("Hello World!", 200, headers)
headers内の"Access-Control-Allow-Origin": "*" 部分でOriginを指定することができます。