🦁
NestJSでのCORSエラーを解消する
開発時にNext.jsからNestJSへデータfetchするとCORSエラーが起きました
- cosoleでのエラー文
Access to fetch at '<Next.jsアプリのlocalhost>' from origin '<NestJSアプリのlocalhost>' has been blocked by CORS policy: 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.
解消まで時間がかかったので備忘録として残します
CORSとは
-
CORS(Cross-Origin Resource Sharing) = オリジン間リソース共有
- 追加のHTTPヘッダーを使用して、あるオリジンで動作しているアプリケーションに、
異なるオリジンにあるリソースへのアクセス権を与えるようにブラウザに指示を出すための仕組み - 異なるオリジンに対して、アクセスを制限することで以下のような脆弱性を防げる
- XSS
- CSRF
- 追加のHTTPヘッダーを使用して、あるオリジンで動作しているアプリケーションに、
-
オリジン = プロトコル + ドメイン + ポート番号
- https://foo.com:443 = https:// + foo.com + 443
-
オリジン間HTTPリクエスト
- 異なるオリジンにあるリソースへリクエストするときに実行する
例
https://foo.com
で提供されているフロントエンドから、XMLHttpRequest
を使用して、https://bar.com
で提供されているバックエンドAPIへリクエストを行うような場合
- ブラウザはスクリプトによって開始されるオリジン間HTTPリクエストを制限している
-
XMLHttpRequest
やFetchAPI
は同じオリジンのリソースのみリクエストを行うことができる(=同一オリジンポリシー) - それ以外のオリジンからの場合は正しいCORSヘッダーを含んでいる必要がある
-
HTTPヘッダーでのやりとり
- リクエストヘッダー
-
Origin
が含まれており、ここで判定をする
-
GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://foo.example
- レスポンスヘッダー
-
Access-Control-Allow-Origin
でアクセスできるドメインを制御 - 以下のレスポンスヘッダーでは、すべてのドメインからアクセスできることを示している
-
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml
[…XML データ…]
NestJSでCORSを許可する
ヘッダーには確かにAccess-Control-Allow-Origin
やAccess-Control-Allow-Headers
情報が付与されていない
Middleware
NestJSのMiddlewareを用いてResponseオブジェクトのヘッダーに情報を付与する
MiddlewareとはClientからのRequestがNestJSのRouteHandlerに到達する前に、RequestオブジェクトやResponseオブジェクトに介入できる仕組み
cors.middleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
@Injectable()
export class CorsMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
res.header('Access-Control-Allow-Origin', '*');
res.header(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept',
);
next();
}
}
作成したcors.middleware.ts
をapp.module.ts
に適用させる
app.module.ts
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { CorsMiddleware } from './cors.middleware';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(CorsMiddleware).forRoutes('*');
}
}
ヘッダーにAccess-Control-Allow-Origin
やAccess-Control-Allow-Headers
情報が付与されるようになった
その他の解決策
- app.enableCors()
- NestJSアプリのbootstrap時に
enableCors
関数を適用させる方法- 調べたらよく出てくる解決策
- 何故か上手くいかなかった
- Next.jsでのリクエストの仕方の問題?
- SWRを使ってfetchしている
- Next.jsでのリクエストの仕方の問題?
- NestJSアプリのbootstrap時に
参考
- CORSの仕組み
- NestJSでのCORS許可
- NestJSのMiddleware
Discussion