๐ํ์๋ ๋ฐฑ์๋ ์๋ฒ๋ฅผ ๋ง๋ค๊ธฐ ๋๋ฌธ์ ํ๋ก ํธ์๋์ ๋๋ฉ์ธ์ ์ค๋ฆฌ์ง์ด ๋ค๋ฅด๋ค. ๋ฐ๋ผ์ ์๋ก ๋ฆฌ์์ค๋ฅผ ์ฃผ๊ณ ๋ฐ๊ธฐ์ํด์ ๋ฐ๋์ CORS์ค์ ์ ํด์ค์ผ ํ๋ค.
NestJS์์๋ CORS(Cross-Origin Resource Sharing) ์ค์ ์ ํตํด SOP์ ํด๋นํ์ง ์๋ ๋ค๋ฅธ ๋๋ฉ์ธ์ ๋ฆฌ์์ค๋ฅผ ๋ฐ๊ธฐ์ํ ๋ฐฉ๋ฒ์ ๊ฐ๋จํ๊ฒ ์ ๊ณตํ๋ค.
NestJS์ ๊ณต์ ํ์ด์ง์์๋ ์๋์ ๊ฐ์ ์ฝ๋๋ค๋ก CORS์ค์ ์ ํ ์ ์๋ค๊ณ ์ ์ํ๋ค.
const app = await NestFactory.create(AppModule);
app.enableCors();
await app.listen(3000);
//--------------------------์ ๋๋ ์๋ ๋ฐฉ๋ฒ
const app = await NestFactory.create(AppModule, { cors: true });
await app.listen(3000);
๋ ๊ฐ์ง์ ๋ฐฉ๋ฒ์ ์ ์ํด ์ฃผ๋ฉฐ, ์ด ๋ฐฉ๋ฒ๋ค์ ๊ธฐ๋ณธ์ ์ผ๋ก Express corsํจํค์ง๋ฅผ ๋ด๋ถ์ ์ผ๋ก ์ฌ์ฉํ๋ค.
์์ ๋ ๊ฐ์ง ๋ฐฉ๋ฒ ๋ชจ๋ ๊ธฐ๋ณธ๊ฐ์ ์ ์ฉ์ํค๊ธฐ ๋๋ฌธ์ ๊ธฐ๋ณธ์ต์ ์ด ์ด๋ป๊ฒ ์ค์ ๋๋์ง ์ ํ์๊ฐ ์๋ค.
์์ ๋ฐฉ๋ฒ๋๋ก CORS๋ฅผ ์ค์ ํ๋ฉด ์ค์ ๋ ๊ธฐ๋ณธ์ต์ (default)์ ๋ค์๊ณผ ๊ฐ๋ค.
{
"origin": "*",
"methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
"preflightContinue": false,
"optionsSuccessStatus": 204
}
ํ์ง๋ง ์ฐ๋ฆฌ๋ ์ฐ๋ฆฌ๊ฐ ์ํ๋ ์ต์ ๋ง ์ฌ์ฉํ๊ณ ์ถ์ ์ ์๋ค. ๊ทธ๋ ๋ค๋ฉด ์ด๋ค ์ต์ ์ ์ค์ ํ ์ ์๋์ง ์์๋ด์ผ ๊ฒ ๋ค.
.enableCors()ํจ์๋ฅผ ctrl+click์ผ๋ก step-inํด์ option์ ์ฐพ์๊ฐ๋ณด๋ฉด CorsOption์ ์ธํฐํ์ด์ค๋ฅผ ํ์ธํ ์ ์๋ค.
export interface CorsOptions {
/**
* Configures the `Access-Control-Allow-Origins` CORS header.
See [here for more detail.](https://github.com/expressjs/cors#configuration-options)
์ด๋ค ์ค๋ฆฌ์ง๊ณผ ์ฐ๊ฒฐ์ ํ์ฉํ ๊ฒ์ธ๊ฐ? ๊ธฐ๋ณธ๊ฐ true or "*" */
// type StaticOrigin = boolean | string | RegExp | (string | RegExp)[]
// type CustomOrigin = (requestOrigin: string, callback: (err: Error | null, origin?: StaticOrigin) => void) => void
origin?: StaticOrigin | CustomOrigin;
/**
* Configures the Access-Control-Allow-Methods CORS header.
์ด๋ค ๋ฉ์๋์ ์ฐ๊ฒฐ์ ํ์ฉํ ๊ฒ์ธ๊ฐ?*/
methods?: string | string[];
/**
* Configures the Access-Control-Allow-Headers CORS header.
์ด๋ค ํค๋๋ฅผ ๋ณด๋ผ ์ ์๋๋ก ํ ๊ฒ์ธ๊ฐ?*/
allowedHeaders?: string | string[];
/**
* Configures the Access-Control-Expose-Headers CORS header.
๋ธ๋ผ์ฐ์ ์์ ์ด๋ค ํด๋๋ฅผ ๋
ธ์ถํ ๊ฒ์ธ๊ฐ?*/
exposedHeaders?: string | string[];
/**
* Configures the Access-Control-Allow-Credentials CORS header.
์ฟ ํค, ์ธ์ฆ ํค๋ ๋ฑ์ ์ฌ์ฉํ ์ ์๊ฒ ํ ๊ฒ์ธ๊ฐ?*/
credentials?: boolean;
/**
* Configures the Access-Control-Max-Age CORS header.
CORS ํ๋ฆฌํ๋ผ์ดํธ ์์ฒญ ๊ฒฐ๊ณผ๋ฅผ ์บ์ฑํ ์๊ฐ์ ๋ช์ผ๋ก ์ค์ ํ ๊ฒ์ธ๊ฐ?*/
maxAge?: number;
/**
* Whether to pass the CORS preflight response to the next handler.
CORS ํ๋ฆฌํ๋ผ์ดํธ ์์ฒญ์ ๋ํ ์๋ต์ด ๋ค์ ๋ฏธ๋ค์จ์ด๋ก ์ ๋ฌ๋๋๋ก ํ ๊ฒ์ธ๊ฐ? ๊ธฐ๋ณธ๊ฐ false*/
preflightContinue?: boolean;
/**
* Provides a status code to use for successful OPTIONS requests.
์ฑ๊ณต์ ์ธ OPTIONS ์์ฒญ์ ๋ํ ์๋ต ์ํ ์ฝ๋๋ฅผ ์ด๋ค๊ฒ์ ๋ณด๋ผ ๊ฒ์ธ๊ฐ? ๊ธฐ๋ณธ๊ฐ 204*/
optionsSuccessStatus?: number;
}
๋ง์ฝ ๋ด๊ฐ ๋ชจ๋ ๋๋ฉ์ธ ์ค๋ฆฌ์ง์ ๋ํด์ ํ์ฉํ๊ณ , Authํค๋๋ฅผ ๋ธ๋ผ์ฐ์ ์์ ์ฌ์ฉํ๊ณ , ์ฟ ํค๋ฅผ ์ฌ์ฉํ๊ณ ์ถ๋ค๋ฉด ์๋์ ๊ฐ์ ํํ๊ฐ ๋ ๊ฒ์ด๋ค.
app.enableCors({
origin: true,
credentials: true,
exposedHeaders: ['Authorization'], // * ์ฌ์ฉํ ํค๋ ์ถ๊ฐ.
});
๊ทธ๋ ๋ค๋ฉด ๋ชจ๋ ์ค๋ฆฌ์ง์ด ์๋ ์ฐ๋ฆฌ ํ๋ก ํธ์์ ๋ฐฐํฌํ ์๋ฒ์ ์ค๋ฆฌ์ง(https://www.example.shop
)๊ณผ ํ๋ก ํธ์๋์์ ๊ฐ๋ฐ์ ์ํ ๋ก์ปฌ์๋ฒ์ ์ค๋ฆฌ์ง(http://localhost:3330
)์ ๋ํด์๋ง ์ค์ ํ๊ณ ์ถ๋ค๋ฉด?
app.enableCors({
origin: ['https://www.example.shop', 'http://localhost:3330'],
credentials: true,
exposedHeaders: ['Authorization'], // * ์ฌ์ฉํ ํค๋ ์ถ๊ฐ.
});
๋ ๊ฐ์ง origin์ ์ฒ์ ์ค์ ํ ๋๋ port์ ๊ตฌ๋ถ์ฒ๋ผ process.env.port | 3300
๊ณผ ๊ฐ์ด ์ฐ๋ ๊ฒ์ด๋ผ ์๊ฐํด์ ์์ฑํด ๋ณด์์ง๋ง ๋์ํ์ง ์์ ํ์ธํด๋ณด๋ |
์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ ์ ์์๋ค. origin์ต์
์ StaticOrigin์ ์ ์ค์ ์ ์ฃผ์๊ณผ ๊ฐ์ด boolean | string | RegExp | (string | RegExp)[]์ ํ์
์ ์ง์ํ๊ธฐ ๋๋ฌธ์ ์์ ์ฝ๋์ฒ๋ผ ํ์ํ ๋๋ฉ์ธ์ ๋ฐฐ์ด์ ํํ๋ก ๋ฃ์ด์ฃผ์ด์ผ ์ํ๋ ๋๋ฉ์ธ๋ค์ ์ค์ ํ ์์๋ค.
์ ๋ณด์์ต๋๋ค.
export interface CorsOptions ์ ์ฃผ์๋ถ๋ถ๋ค์ ์ง์ ํ๊ธ๋ก ๋ฐ๊พธ์ ๊ฑด๊ฐ์??