API Gateway 생성 시 발생하는 No ‘Access-Control-Allow-Origin’ 문제 해결
안녕하세요 클래스메소드 김재욱(Kim Jaewook) 입니다. 이번에는 API Gateway 생성 시 발생하는 No ‘Access-Control-Allow-Origin’ 문제를 해결하는 방법에 대해서 정리해 봤습니다.
문제 발생
Amplify를 통해 웹 사이트를 배포하고 있는 환경에서 No ‘Access-Control-Allow-Origin 에러가 발생했습니다.
API Gateway와 Lambda는 문제없이 연결된 상태입니다.
하지만, API Gateway의 엔드포인트로 접근해 보면 에러가 발생하고 있는 것을 확인할 수 있습니다.
API Gateway와 Lambda 사이에서 제대로 연동이 이루어지지 않은 것 같습니다.
문제 해결
CORS 즉, Cross-Origin Resource Sharing는 오리진 간 리소스를 공유하는 역할을 수행합니다. 이번에 구축한 웹 호스팅을 수행하는 사이트는 AWS Amplify에 JS, HTML 파일을 업로드하며, 이 파일에는 Ajax 등을 사용하여 API Gateway의 API에 접근을 수행하는 코드를 담고 있습니다. 여기서 Ajax 등으로 다른 오리진(API Gateway의 API)으로 접근하기 위해서는 CORS를 활성화할 필요가 있습니다.
기본적으로 스키마, 호스트 및 포트가 모두 일치하는 경우에만 동일한 오리진이라고 말할 수 있습니다. 그렇다면 여기서 말하는 동일한 오리진은 무엇일까요? 예시를 들어보면 다음과 같습니다.
- http://jaewook.com/app1/index.html
- http://jaewook.com/app2/index.html
- http://Jaewook.com:80
- http://jaewook.com
스키마, 호스트 및 포트가 전부 동일하기 때문에 동일한 오리진이라고 볼 수 있습니다. 반대로 다른 오리진에 대한 예시를 살펴보면 다음과 같습니다.
- http://jaewook.com/app1/index.html
- https://jaewook.com/app2/index.html
- http://www.jaewook.com/app2/index.html
- http:/jaewook.com/app2/index.html:8080
확인해 보면, 스키마, 호스트, 포트가 각기 다르므로 동일한 오리진이 아니라는 것을 한 번에 확인할 수 있습니다. 보다 명확한 이유는 아래에서 설명하고 있습니다.
- 보안상의 이유로 브라우저는 스크립트에 의한 오리진 간 HTTP 요청을 제한하고 있으며 JavaScript의 XMLHttpRequests, Fetch 등의 API는 동일한 오리진 정책을 따릅니다.
- 동일한 오리진 정책에 의해, 보안은 지켜지지만, Ajax등의 통신을 이용한 경우 등 유연성이 부족하다.
- 웹 통신의 전제로서 동일한 오리진 접속, 다른 오리진에 액세스하는 경우는 CORS에 의해 통신을 실시할 필요가 있다.
CloudFormation을 사용하는 경우 API Gateway에 다음 코드를 삽입합니다.
IntegrationResponses: - StatusCode: 200 ResponseParameters: method.response.header.Access-Control-Allow-Origin: "'*'" method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'" method.response.header.Access-Control-Allow-Methods: "'POST,OPTIONS'" MethodResponses: - StatusCode: 200 ResponseParameters: method.response.header.Access-Control-Allow-Origin: true method.response.header.Access-Control-Allow-Headers: true method.response.header.Access-Control-Allow-Methods: true
각 메소드에 CORS를 활성화시키는 코드를 삽입합니다.
ApiGatewayOptionsMethod: Type: AWS::ApiGateway::Method Properties: AuthorizationType: NONE HttpMethod: OPTIONS ResourceId: Fn::GetAtt: [ApiGatewayRestApi, RootResourceId] RestApiId: !Ref ApiGatewayRestApi Integration: IntegrationHttpMethod: OPTIONS Type: MOCK IntegrationResponses: - StatusCode: 200 ResponseParameters: method.response.header.Access-Control-Allow-Origin: "'*'" method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'" method.response.header.Access-Control-Allow-Methods: "'GET,POST,OPTIONS'" PassthroughBehavior: WHEN_NO_TEMPLATES RequestTemplates: application/json: "{\"statusCode\": 200}" MethodResponses: - StatusCode: 200 ResponseParameters: method.response.header.Access-Control-Allow-Origin: true method.response.header.Access-Control-Allow-Headers: true method.response.header.Access-Control-Allow-Methods: true
이어서 옵션 메소드를 추가해주면 됩니다.
콘솔 화면에서의 CORS 설정은 다음 블로그를 참고해 주세요.
CORS를 설정하고 다시 웹 사이트에 접근해 보면, 성공적으로 데이터가 불러와지는 것을 확인할 수 있습니다.
본 블로그 게시글을 읽고 궁금한 사항이 있으신 분들은 [email protected]로 보내주시면 감사하겠습니다.