[CORS에러] Cross-origin Resource Sharing 허용하기
상황 :
python3로 서버를 만들었고,
python3 app.py runserver를 통해 서버를 실행했다.
React로 프론트엔드를 만들었고,
npm start를 통해 로컬 서버를 실행시켰다.
프론트엔드에서는 서버의 http://localhost:[포트번호]로 요청을 보내어
서버에 있는 데이터를 받아와서
브라우저 화면에 렌더링해 주었는데,
그때 CORS에러가 발생하였다 ㅠㅠㅠㅠ
그래서 CORS가 뭔데???
보안 상의 이유로, 브라우저는 스크립트에서 시작한 교차 출처 HTTP 요청을 제한한다.
예를 들어, XMLHttpRequest와 Fetch API는 동일 출처 정책을 따른다.
즉, 이 API를 사용하는 웹 애플리케이션은 자신의 출처와 동일한 리소스만 불러올 수 있으며,
다른 출처의 리소스를 불러오려면 그 출처에서 올바른 CORS 헤더를 포함한 응답을 반환해야 한다.
Cross-Origin 리소스 메커니즘
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
Cross-Origin Resource sharing은 HTTP헤더에 기초한 메커니즘이다.
자기자신의 브라우저가 아닌 곳으로부터 서버가 어떤 출처든(도메인, 스키마, 혹은 포트)
브라우저가 리소스를 허용하는 메커니즘이다.
CORS 메커니즘은 브라우저가
자기자신이 아닌 출처의 리소스를 호스팅하는 서버에 'preflight' 요청을 함으로써
서버가 실제 요청을 허용할 것인지 체크한다.
그 preflight을 통해 브라우저는 HTTP메서드와 헤더를 가지고 있는 헤더를 전송하며,
그것은 실제 요청에서 사용된다.
보안적인 이유로 브라우저는 스크립트로 접한 cross-origin HTTP요청을 제한한다.
(XMLHTTPRequest와 Fetch API는 동일 출처 정책을 따른다.
웹 애플리케이션이 이런 API를 사용하는것은
(앱이 올바른 CORS헤더를 포함하고 있는 다른 출처에서의 응답이 아니고서는)
동일 출처 앱으로부터만이 요청할 수 있다.
cross-origin sharing standard 를 통해 크로스 오리진 접근이 가능해진다.
Cross-origin sharing standard
교차출처의 응답을 허용하기 위해,
또한 html form엘리먼트로 가능한것 보다 더 다양한 fetch를 허용하기 위해,
CORS 프로토콜이 존재한다.
HTTP위에 계층이 적용된 것이며, 다른 출처와 공유될 수 있게 허용해준다.
구성
CORS 프로토콜은 응답이 교차출처와 공유될 수 있는지 가리키는 헤더들로 구성되어있다.
form엘리먼트보다 더 많은 것을 가능하게 하는 요청을 위해
CORS-preflight 요청이 수행되며
이 요청의 현재 URL은 CORS 프로토콜을 지원하도록 하기 위해 CORS-preflight 요청이 수행된다.
HTTP 요청들
CORS요청은 Origin헤더를 포함하고 있는 HTTP요청이다.
Origin header는 GET이나 HEAD가 아닌 메소드의 요청에도 포함되기 때문에
믿을만 하게 확인될수는 없다
CORS-preflight요청은 CORS 프로토콜이 받아들여지고 있는지 확인하는 요청이다.
OPTIONS를 메소드로 사용하며, 아래의 헤더들을 포함한다.
Access-Control-Request-Method
동일한 리소스를 위해 미래의 CORS요청에서 어떤 메소드를 사용할 것인지 지정함
Access-Control-Request-Headers
동일한 리소스를 위해 미래의 CORS요청에서 어떤 메소드를 사용할 것인지 지정함
HTTP 응답들
CORS요청에 대한 HTTP응답은 아래의 headers를 포함할 수 있다.
Access-Control-Allow-Origin
응답에서 리터럴 값인 Origin 요청의 헤더(null가능) 혹은 * 을 돌려주는 것으로 응답이 공유될 수 있는지 지정함.
Access-Control-Allow-Credentials
요청의 credentials 모드가 include일 때 응답이 공유될 수 있는지 여부를 지정함.
CORS preflight요청에 대해 요청의 credentials모드는 언제나 'same-origin'이다.
즉, credentials를 배제하지만 어떤 추후의 CORS 요청은 그러지 않을 수 있다.
https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
에러가 해결되었다!!!!
이번에 에러가 난 것은 여기였다.
즉, python 서버에서 응답을 만들 때,
다른 Headers는 찾아서 넣어주었는데,
지금 이 Headers를 넣지 않았기 때문에
브라우저가 이 응답을 무시했던 것이다.
반드시 !!!! true로 해줄 것!!!!
파이썬 Header 삽입 코드 전문
import logging
from flask import Flask, render_template, jsonify, request, make_response
from flask_cors import CORS
app = Flask(__name__)
CORS(app, supports_credentials=True)
contents = [
{
'board_id': 1,
'category': "talk",
'title': "제목",
'writer': "jane",
'content': "Hi!!! How nice the weather!",
'regdate': "2023-09-16",
},
{
'board_id': 2,
'category': "share",
'title': "제목2",
'writer': "Peter",
'content': "I'm studying React now!!!",
'regdate': "2023-09-12",
},
{
'board_id': 3,
'category': "question",
'title': "제목3",
'writer': "zenkins",
'content': "What on earth is React?",
'regdate': "2023-09-12",
},
]
@app.route('/', methods=['GET', 'OPTIONS'])
def render_home() :
return jsonify('Hello')
@app.route('/total', methods=['GET', 'OPTIONS'])
def render_contents():
if request.method == 'OPTIONS':
response = make_response()
response.headers.add('Access-Control-Allow-Origin', 'http://localhost:3000')
response.headers.add('Access-Control-Allow-Headers', 'Content-Type')
response.headers.add('Access-Control-Allow-Methods', 'GET')
response.headers.add('Access-Control-Allow-Credentials', 'true')
return response
else:
return jsonify(contents)
app.logger.setLevel(logging.INFO)
app.logger.info("Flask app is running")
logging.basicConfig(filename='app.log', level=logging.INFO)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5001, debug=True, use_reloader=True, )
참고
https://velog.io/@logqwerty/CORS
https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
https://fetch.spec.whatwg.org/#http-cors-protocol
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials