[jquery] 플라스크에서 CORS를 활성화하는 방법

jquery를 사용하여 원본 간 요청을 시도하고 있지만 메시지와 함께 계속 거부됩니다.

XMLHttpRequest에서 http : //를로드 할 수 없습니다 … 요청 된 리소스에 ‘Access-Control-Allow-Origin’헤더가 없습니다. 따라서 Origin … 액세스가 허용되지 않습니다.

나는 flask, heroku 및 jquery를 사용하고 있습니다.

클라이언트 코드는 다음과 같습니다.

$(document).ready(function() {
    $('#submit_contact').click(function(e){
        e.preventDefault();
        $.ajax({
            type: 'POST',
            url: 'http://...',
            // data: [
            //      { name: "name", value: $('name').val()},
            //      { name: "email", value: $('email').val() },
            //      { name: "phone", value: $('phone').val()},
            //      { name: "description", value: $('desc').val()}
            //
            // ],
            data:"name=3&email=3&phone=3&description=3",
            crossDomain:true,
            success: function(msg) {
                alert(msg);
            }
        });
    });
});

헤 로쿠 쪽은 플라스크를 사용하고 있는데 이렇게

from flask import Flask,request
from flask.ext.mandrill import Mandrill
try:
    from flask.ext.cors import CORS  # The typical way to import flask-cors
except ImportError:
    # Path hack allows examples to be run without installation.
    import os
    parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    os.sys.path.insert(0, parentdir)

    from flask.ext.cors import CORS
app = Flask(__name__)

app.config['MANDRILL_API_KEY'] = '...'
app.config['MANDRILL_DEFAULT_FROM']= '...'
app.config['QOLD_SUPPORT_EMAIL']='...'
app.config['CORS_HEADERS'] = 'Content-Type'

mandrill = Mandrill(app)
cors = CORS(app)

@app.route('/email/',methods=['POST'])
def hello_world():
    name=request.form['name']
    email=request.form['email']
    phone=request.form['phone']
    description=request.form['description']

    mandrill.send_email(
        from_email=email,
        from_name=name,
        to=[{'email': app.config['QOLD_SUPPORT_EMAIL']}],
        text="Phone="+phone+"\n\n"+description
    )

    return '200 OK'

if __name__ == '__main__':
    app.run()



답변

Heroku에 배포했을 때 효과가 있었던 것은 다음과 같습니다.

http://flask-cors.readthedocs.org/en/latest/

다음을 실행하여 flask-cors를 설치합니다.
pip install -U flask-cors

from flask import Flask
from flask_cors import CORS, cross_origin
app = Flask(__name__)
cors = CORS(app)
app.config['CORS_HEADERS'] = 'Content-Type'

@app.route("/")
@cross_origin()
def helloWorld():
  return "Hello, cross-origin-world!"


답변

좋아요, galuszkak에서 언급 한 공식 스 니펫이 모든 곳에서 사용되어야한다고 생각하지 않습니다 hello_world. 함수 와 같은 핸들러 중에 일부 버그가 트리거 될 수있는 경우를 고려해야합니다 . 응답이 정확하든 부정확하든 Access-Control-Allow-Origin헤더는 우리가 관심을 가져야 할 것입니다. 따라서 다음과 같이 매우 간단합니다.

@blueprint.after_request # blueprint can also be app~~
def after_request(response):
    header = response.headers
    header['Access-Control-Allow-Origin'] = '*'
    return response

그게 다야 ~~


답변

나는 방금 같은 문제에 직면했고 다른 답변이 필요한 것보다 조금 더 복잡하다고 믿게되었으므로 더 많은 라이브러리 나 데코레이터에 의존하고 싶지 않은 사람들을위한 나의 접근 방식은 다음과 같습니다.

CORS 요청은 실제로 두 개의 HTTP 요청으로 구성됩니다. 프리 플라이트 요청과 프리 플라이트가 성공적으로 통과 한 경우에만 수행되는 실제 요청입니다.

프리 플라이트 요청

실제 교차 도메인 POST요청 전에 브라우저가 OPTIONS요청 을 발행합니다 . 이 응답은 본문을 반환해서는 안되지만 브라우저에이 교차 도메인 요청을 수행해도 괜찮으며 일부 교차 사이트 스크립팅 공격의 일부가 아니라는 것을 알리는 일부 안심 헤더 만 반환해야합니다.

모듈 의 make_response함수를 사용하여이 응답을 빌드하는 Python 함수를 작성했습니다 flask.

def _build_cors_prelight_response():
    response = make_response()
    response.headers.add("Access-Control-Allow-Origin", "*")
    response.headers.add("Access-Control-Allow-Headers", "*")
    response.headers.add("Access-Control-Allow-Methods", "*")
    return response

이 응답은 모든 요청에 ​​대해 작동하는 와일드 카드 응답입니다. CORS에서 추가 보안을 확보하려면 출처, 헤더 및 메소드의 화이트리스트를 제공해야합니다.

이 응답은 (Chrome) 브라우저가 계속해서 실제 요청을 수행하도록 설득합니다.

실제 요청

실제 요청을 처리 할 때 하나의 CORS 헤더를 추가해야합니다. 그렇지 않으면 브라우저가 호출하는 JavaScript 코드에 대한 응답을 반환하지 않습니다. 대신 클라이언트 측에서 요청이 실패합니다. jsonify를 사용한 예

response = jsonify({"order_id": 123, "status": "shipped"}
response.headers.add("Access-Control-Allow-Origin", "*")
return response

나는 또한 그것을위한 함수를 썼다.

def _corsify_actual_response(response):
    response.headers.add("Access-Control-Allow-Origin", "*")
    return response

한 줄로 되돌릴 수 있습니다.

최종 코드

from flask import Flask, request, jsonify, make_response
from models import OrderModel

flask_app = Flask(__name__)

@flask_app.route("/api/orders", methods=["POST", "OPTIONS"])
def api_create_order():
    if request.method == "OPTIONS": # CORS preflight
        return _build_cors_prelight_response()
    elif request.method == "POST": # The actual request following the preflight
        order = OrderModel.create(...) # Whatever.
        return _corsify_actual_response(jsonify(order.to_dict()))
    else
        raise RuntimeError("Weird - don't know how to handle method {}".format(request.method))

def _build_cors_prelight_response():
    response = make_response()
    response.headers.add("Access-Control-Allow-Origin", "*")
    response.headers.add('Access-Control-Allow-Headers', "*")
    response.headers.add('Access-Control-Allow-Methods', "*")
    return response

def _corsify_actual_response(response):
    response.headers.add("Access-Control-Allow-Origin", "*")
    return response


답변

모든 경로에 대해 CORS를 활성화하려면 flask_cors 확장 ( pip3 install -U flask_cors)을 설치하고 다음 과 app같이 래핑 CORS(app)합니다..

그것으로 충분합니다 ( POST이미지 업로드 요청으로 이것을 테스트 했으며 저에게 효과적이었습니다).

from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app) # This will enable CORS for all routes

중요 사항 : 경로에 오류가있는 경우 존재하지 않는 변수를 인쇄하려고하면 실제로 CORS와 관련이없는 CORS 오류 관련 메시지가 표시됩니다.


답변

다음 데코레이터를 사용해보세요.

@app.route('/email/',methods=['POST', 'OPTIONS']) #Added 'Options'
@crossdomain(origin='*')                          #Added
def hello_world():
    name=request.form['name']
    email=request.form['email']
    phone=request.form['phone']
    description=request.form['description']

    mandrill.send_email(
        from_email=email,
        from_name=name,
        to=[{'email': app.config['QOLD_SUPPORT_EMAIL']}],
        text="Phone="+phone+"\n\n"+description
    )

    return '200 OK'

if __name__ == '__main__':
    app.run()

이 데코레이터는 다음과 같이 생성됩니다.

from datetime import timedelta
from flask import make_response, request, current_app
from functools import update_wrapper


def crossdomain(origin=None, methods=None, headers=None,
                max_age=21600, attach_to_all=True,
                automatic_options=True):

    if methods is not None:
        methods = ', '.join(sorted(x.upper() for x in methods))
    if headers is not None and not isinstance(headers, basestring):
        headers = ', '.join(x.upper() for x in headers)
    if not isinstance(origin, basestring):
        origin = ', '.join(origin)
    if isinstance(max_age, timedelta):
        max_age = max_age.total_seconds()

    def get_methods():
        if methods is not None:
            return methods

        options_resp = current_app.make_default_options_response()
        return options_resp.headers['allow']

    def decorator(f):
        def wrapped_function(*args, **kwargs):
            if automatic_options and request.method == 'OPTIONS':
                resp = current_app.make_default_options_response()
            else:
                resp = make_response(f(*args, **kwargs))
            if not attach_to_all and request.method != 'OPTIONS':
                return resp

            h = resp.headers

            h['Access-Control-Allow-Origin'] = origin
            h['Access-Control-Allow-Methods'] = get_methods()
            h['Access-Control-Max-Age'] = str(max_age)
            if headers is not None:
                h['Access-Control-Allow-Headers'] = headers
            return resp

        f.provide_automatic_options = False
        return update_wrapper(wrapped_function, f)
    return decorator

이 패키지 Flask-CORS를 확인할 수도 있습니다.


답변

내 솔루션은 app.route를 둘러싼 래퍼입니다.

def corsapp_route(path, origin=('127.0.0.1',), **options):
    """
    Flask app alias with cors
    :return:
    """

    def inner(func):
        def wrapper(*args, **kwargs):
            if request.method == 'OPTIONS':
                response = make_response()
                response.headers.add("Access-Control-Allow-Origin", ', '.join(origin))
                response.headers.add('Access-Control-Allow-Headers', ', '.join(origin))
                response.headers.add('Access-Control-Allow-Methods', ', '.join(origin))
                return response
            else:
                result = func(*args, **kwargs)
            if 'Access-Control-Allow-Origin' not in result.headers:
                result.headers.add("Access-Control-Allow-Origin", ', '.join(origin))
            return result

        wrapper.__name__ = func.__name__

        if 'methods' in options:
            if 'OPTIONS' in options['methods']:
                return app.route(path, **options)(wrapper)
            else:
                options['methods'].append('OPTIONS')
                return app.route(path, **options)(wrapper)

        return wrapper

    return inner

@corsapp_route('/', methods=['POST'], origin=['*'])
def hello_world():
    ...


답변

여기에 설명 된 솔루션 개선 : https://stackoverflow.com/a/52875875/10299604

이를 통해 after_requestCORS 응답 헤더를 처리하여 엔드 포인트에 추가 코드를 추가하지 않아도됩니다.

    ### CORS section
    @app.after_request
    def after_request_func(response):
        origin = request.headers.get('Origin')
        if request.method == 'OPTIONS':
            response = make_response()
            response.headers.add('Access-Control-Allow-Credentials', 'true')
            response.headers.add('Access-Control-Allow-Headers', 'Content-Type')
            response.headers.add('Access-Control-Allow-Headers', 'x-csrf-token')
            response.headers.add('Access-Control-Allow-Methods',
                                'GET, POST, OPTIONS, PUT, PATCH, DELETE')
            if origin:
                response.headers.add('Access-Control-Allow-Origin', origin)
        else:
            response.headers.add('Access-Control-Allow-Credentials', 'true')
            if origin:
                response.headers.add('Access-Control-Allow-Origin', origin)

        return response
    ### end CORS section