CORS관련 에러
17 Jun 2020환경
API
- Python 3.7.7
- Django 3.0.7
- djangorestframework 3.11.0
Client
- Node.js 8.12.0
- Vue.js 2.6.11
- Vuex 3.4.0
오류
Vue.js를 이용한 실습예제을 마치고, 예제로 주어진 Node.js 서버가 아닌 Django-REST를 이용해 직접 구현해 보고자 하였다. Client와 API서버를 로컬환경에서 실행했을 때, Client가 리스트를 받아오지 않는 문제가 발생하였고, 오류메시지는 다음과 같았다.
해당 오류메시지를 검색해보고 CORS에러 문제라는 것을 알게 되었다.
CORS
CORS는 Cross-Origin Resource Sharing의 약자로 브라우저의 현재 웹페이지가 이 페이지를 받은 서버가 아닌 다른 서버의 자원을 호출하는 것을 의미한다. 쉽게 말하자면 데이터를 보내고 받는 사이트의 주소가 다를때, 이를 허용해 주는 것이다.
이번 CORS 관련 오류는 정책인 동일 출처 정책(same-origin policy)으로 인해서 발생하는 것이다. 이러한 문제를 해결하기 위해서는 Client와 API 서버에서의 수정을 요구한다.
Client
CORS에서 Client서버에서 외부에 데이터를 보내기 위해 사전 요청(preflight request)을 하게된다. 사전 요청을 통해서 Client는 API 서버에 요청을 할 수 있는 권한이 있는지 확인을 하게 된다. Client의 요청 헤더는 다음과 같다.
- Origin : 요청을 보내는 페이지의 출처(도메인)
- Access-Control-Request-Method : 실제 요청하려는 메서드
- Access-Control-Request-Headers : 실제 요청에 포함되어 있는 해더 이름
API 서버
API서버에서는 요청을 받고 권한에 요청 정보를 보내게 된다. API 서버의 요청 헤더는 다음과 같다.
- Access-Control-Allow-Origin : 요청을 허락하는 출처
- Access-Control-Allow-Credentials : Client 요청이 쿠키를 통해서 자격 증명을 해야하는 경우에 true값을 가진다. 만약 true일 경우 응답받은 클라이 언트는 실제 요청시 서버에서 정의된 규격의 인증값이 담긴 쿠키를 같이 보내야 한다.
- Access-Control-Expose-Headers : Client 요청에 포함되어도 되는 사용자 정의 헤더
- Access-Control-Max-Age : Client에서 사전 요청 결과를 저장할 기간
- Access-Control-Allow-Methods : 요청을 허락하는 메서드, 기본값은 [GET, POST]
- Access-Control-Allow-Headers : 요청을 허용하는 해더
해결
이번 CORS 에러에 대해서는 Client에서의 수정을 하지않고 해결할 수 있었다. Django에 있는 django-cors-headers
라는 패키지 설치를 통해서 settings.py
에서 CORS를 관리 할 수 있었다.
1. 패키지 설치
$ pip install django-cors-headers
2. 적용
# settings.py
...
INSTALLED_APPS = [
...
'corsheaders',
]
...
MIDDLEWARE = [
...
'corsheaders.middleware.CorsMiddleware',
]
...
# 가장 아래
CORS_ORIGIN_ALLOW_ALL=False # 모든 요청을 허락한다는 헤더
CORS_ALLOW_CREDENTIALS = False # 쿠키관련 헤더
# 아래와 같은 주소는 접근을 허락함
CORS_ORIGIN_WHITELIST = [
"http://localhost:8080",
"http://127.0.0.1:8080"
]
# 아래와 같은 접근을 허락함
CORS_ALLOW_METHODS = (
'DELETE',
'GET',
'POST',
'PUT',
)
# 아래와 같은 헤더를 허락함
CORS_ALLOW_HEADERS = (
'accept',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
)