7. Typescript & Serverless 사용기 - CORS
CORS는 교차 출처 리소스 공유(Corss-Origin Resource Sharing)의 약자로 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제입니다. http 요청 시 웹 페이지의 리소스가 자신의 출처(도메인, 프로토콜, 포트)와 다를 때 교차 출처 http 요청을 실행합니다.
보안상의 이유로, 브라우저에서 교차 출처 http 요청을 제한하는데, 다른 출처의 리소스를 불러오려면 그 출처에서 올바른 CORS헤더를 포함해야 합니다.(설명참조: https://developer.mozilla.org/ko/docs/Web/HTTP/CORS)
CORS문제가 serverless에서 문제가 되는 이유는 서버는 serverless로, 프론트는 aws s3 호스팅이나 다른 호스팅 서비스를 이용할 경우 도메인 출처가 달라져 CORS에러가 발생합니다.
이제 어떤 방식으로 CORS문제를 해결할 수 있는지 알아봅시다.
1. http response에 cors헤더 추가하기
기존에 http.util.ts에 만들어둔 requestSuccess, requestFail 함수에 CORS헤더를 추가해줍니다.
export const responseCorsHeader = {
"Access-Control-Allow-Origin": "*",
'Access-Control-Allow-Credentials': false,
"Content-Type": "application/json",
"Access-Control-Allow-Methods": "OPTIONS,POST,GET,PUT,DELETE"
}
export const requestSuccess = (body, statusCode = 200, headers = {}): APIGatewayProxyResult => {
if (typeof body === 'object') body = JSON.stringify(body, null, 2)
headers = { ...responseCorsHeader, ...headers }
return { headers, statusCode, body }
}
export const requestFail = (body, statusCode = 500, headers = {}): APIGatewayProxyResult => {
if (typeof body === 'object') body = JSON.stringify(body, null, 2)
headers = { ...responseCorsHeader, ...headers }
return { headers, statusCode, body }
}
응답에 CORS요청을 허가하기 위한 Header를 추가했는데, 만드려는 서버의 구성에 따라서 "Access-Control-Allow-Origin" 항목에 허가하려는 URL을 추가해주시면 됩니다.
2. serverless.yml에 CORS옵션 추가
serverless.yml의 functions에 정의된 api에 cors:true 옵션을 넣어줍니다.
functions:
hello:
handler: handler.hello
events:
- http:
method: get
path: hello
cors: true ----------------------------- 추가한 옵션
api_example_post:
handler: api/api_example.api_example_post
events:
- http:
method: post
path: api_example_post
cors: true
1번 작업에서 cors헤더를 추가했지만 functions에서도 한번 더 cors옵션을 넣어줘야 합니다. 그렇지 않으면 우리가 정의한 api에 도달하기 전에 먼저 cors문제가 발생하게 됩니다.
3. serverless.yml - resources 추가
간혹 Api Gateway쪽에서 에러가 발생하는 상황이 생깁니다. 헌데 에러가 발생했음에도 프런트에서 받는 메시지는 CORS에러 메시지를 받을 때가 있습니다.
이런 상황이 벌어지는 이유는 Api Gateway에서 발생한 에러에 CORS헤더가 포함되지 않았기 때문인데 resources에 Gateway response 옵션을 추가해서 정확한 에러 메시지를 받을 수 있습니다.
// serverless.yml
resources:
Resources:
GatewayResponseDefault4XX:
Type: "AWS::ApiGateway::GatewayResponse"
Properties:
ResponseParameters:
gatewayresponse.header.Access-Control-Allow-Origin: "'*'"
gatewayresponse.header.Access-Control-Allow-Headers: "'*'"
ResponseType: DEFAULT_4XX
RestApiId:
Ref: "ApiGatewayRestApi"
GatewayResponseDefault5XX:
Type: "AWS::ApiGateway::GatewayResponse"
Properties:
ResponseParameters:
gatewayresponse.header.Access-Control-Allow-Origin: "'*'"
gatewayresponse.header.Access-Control-Allow-Headers: "'*'"
ResponseType: DEFAULT_5XX
RestApiId:
Ref: "ApiGatewayRestApi"
보시면 ResponseType에 DEFAULT_4XX, DEFAULT_5XX 가 되어있는데 400, 500 에러일 경우 CORS 헤더를 추가해주라는 옵션입니다.
정리
기존에 CORS 문제가 발생하던 api_example_post를 swagger에서 다시 시도해봅시다.
이제 제대로 응답이 오네요.
제가 처음에 serverless 배포했을때 CORS 문제 때문에 꽤 많은 시간을 낭비했었습니다. 다른 분들은 이 글을 보시고 이런 시간낭비가 없었길 바랍니다.