🤢
Next.js appルートでのAPI RoutesのCORS設定
結論
Access-Control-Allowの追加
- "Access-Control-Allow-Origin" は、リクエストオリジンの許可を設定します
- "*" 全オリジンを許可
- "example.app" example.appからのリクエストを許可
- "Access-Control-Allow-Methods" は、リクエストメソッドの許可を設定します
- "GET" GETメソッドを許可
- "GET, POST" GETメソッドとPOSTメソッドを許可
- "Access-Control-Allow-Headers" は、リクエストヘッダーの許可を設定します
- "Content-Type" Content-Typeを許可
- "Content-Type, Authorization" Content-TypeとAuthorizationを許可
export const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
};
corsHeadersを設定
export async function GET(request: Request, response: Response) {
return NextResponse.json(
{ data: 'データ' },
{ status: 200, headers: corsHeaders })
}
全体のコード
app/api/sample/route.ts
export const corsHeaders = {
'Access-Control-Allow-Origin': 'http://localhost:3001', // 許可するオリジン
'Access-Control-Allow-Methods': 'POST, OPTIONS', // 許可するメソッド
'Access-Control-Allow-Headers': 'Content-Type', // 許可するリクエストヘッダー
}
// リクエストヘッダーにContent-Type: "application/json"があると、preflightによりOPTIONSが必要
export async function OPTIONS() {
return NextResponse.json({}, { headers: corsHeaders })
}
export async function GET(request: Request, response: Response) {
// new Responseの書き方
return new Response(JSON.stringify({ data: 'レスポンス' }), {
status: 200,
headers: corsHeaders
})
// NextResponseの書き方
return NextResponse.json(
{ foo: 'bar' },
{ status: 200, headers: corsHeaders })
}
export async function POST(request: Request, response: Response) {
const body = await request.json()
return NextResponse.json(
{ data: "データ", body },
{ status: 200, headers: corsHeaders },
)
}
詰まった点
これでリクエストするとエラーになりました
fetch('http://localhost:3000/api/sample', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
- 探っていくと、
Content-Type: 'application/json'
の設定が問題みたいでした- POSTで、headers, bodyなし OK
- POSTで、bodyあり OK
- POSTで、bodyあり、空header OK
- POSTで、bodyあり、headerに、'Content-Type': 'application/json', ⚠️エラー
- POSTで、bodyあり、headerに、'Content-Type': 'ddddd', OK
エラー内容
Access to fetch at 'http://localhost:3000/api/scoring' from origin 'http://localhost:3001' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
どうやら preflight request
でエラーが出ているので、 preflight request
について調べました
- リクエストヘッダーに'Content-Type': 'application/json'を付けると、preflightというものが送られます。
- preflight request リクエストは始めに
[OPTIONS](https://developer.mozilla.org/ja/docs/Web/HTTP/Methods/OPTIONS)
メソッドによる HTTP リクエストを他のドメインにあるリソースに向けて送り、実際のリクエストを送信しても安全かどうかを確かめます - 今回のAPIはメソッド毎にexportしていて、OPTIONSが存在しないのでエラーが出ていたということです。
解決
-
Access-Control-Allow-Methods
に、OPTIONS
を追加 -
Access-Control-Allow-Headers
に、Content-Type
を追加 -
OPTIONS
を追加
export const corsHeaders = {
'Access-Control-Allow-Origin': 'http://localhost:3001',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', // OPTONSを追加
'Access-Control-Allow-Headers': 'Content-Type', // 追加
}
export async function POST(request: Request, response: Response) {
const body = await request.json()
return NextResponse.json(
{ method: 'POSTです', body },
{ headers: corsHeaders },
)
}
// 追加
export async function OPTIONS() {
return NextResponse.json({}, { headers: corsHeaders })
}
参考
Discussion