aiohttp Server で API サーバを実装する場合の CORS1 対応は、aiohttp 公式で aiohttp_cors というモジュールが用意されている。
しかし Usage を読んでみると、各リソースと各ルートについて cors.add
でラップする必要があり、どうも一筋縄ではいかない雰囲気。細かく設定ができるのは便利だが、「今はとにかくすべてのリクエストを許可したいんや」というケースもある。
そこで今回は、aiohttp_cors を使わずに雑に CORS 対応する方法について書く。
from aiohttp import web
@web.middleware
async def cors_middleware(request, handler):
response = await handler(request)
response.headers['Access-Control-Allow-Origin'] = '*'
return response
app = web.Application(middlewares=[cors_middleware])
終わりです。
すべてのレスポンスに Access-Control-Allow-Origin: *
ヘッダを追加するだけ。
「さすがに *
はどうなの」という場合は環境変数で許可する Origin を指定できるようにするといい。
import os
from aiohttp import web
@web.middleware
async def cors_middleware(request, handler):
response = await handler(request)
response.headers['Access-Control-Allow-Origin'] = os.environ.get('CORS_ALLOW_ORIGIN', '*')
return response
app = web.Application(middlewares=[cors_middleware])
ちなみに Preflight Request が飛ぶケースには対応していない。
対応したければ全ての OPTION
リクエストに対してよしなに返すやつを作ったらいい。
本当に雑な話なので、セキュリティに大丈夫なのとかそのへんの話は各自よしなに考えていってほしい。
[追記] もうちょっとちゃんとした版
- [2022.01 追記] Preflight Request にも対応した
- [2022.02 追記] HTTPException を raise した場合も CORS ヘッダを付与するようにした
from os import getenv
from aiohttp import web
@web.middleware
async def cors_middleware(request, handler):
headers = {
"Access-Control-Allow-Headers": "*",
"Access-Control-Allow-Methods": "*",
"Access-Control-Allow-Origin": getenv("CORS_ALLOW_ORIGIN", "*"),
}
if request.method == "OPTIONS":
return web.Response(headers=headers)
try:
response = await handler(request)
for key, value in headers.items():
response.headers[key] = value
return response
except web.HTTPException as e:
for key, value in headers.items():
e.headers[key] = value
raise e
app = web.Application(middlewares=[cors_middleware])
[追記] Cookie をあつかう場合
Cookie を扱う場合は以下の変更が必要になる。
-
Access-Control-Allow-Credentials
ヘッダにtrue
を設定する必要がある -
Access-Control-Allow-Headers
に*
を指定できなくなるので個別設定する
@web.middleware
async def cors_middleware(request, handler):
headers = {
"Access-Control-Allow-Headers": "Content-Type", # 使用するヘッダを追加していく
"Access-Control-Allow-Methods": "*",
"Access-Control-Allow-Credentials": "true",
"Access-Control-Allow-Origin": getenv("CORS_ALLOW_ORIGIN", "*"),
}
if request.method == "OPTIONS":
return web.Response(headers=headers)
try:
response = await handler(request)
for key, value in headers.items():
response.headers[key] = value
return response
except web.HTTPException as e:
for key, value in headers.items():
e.headers[key] = value
raise e