developer tip

Flask로 교차 오리진 리소스 공유 해결

optionbox 2020. 12. 29. 06:58
반응형

Flask로 교차 오리진 리소스 공유 해결


다음 ajax게시물 요청에 대해 Flask( 플라스크에서 ajax에서 게시 된 데이터를 어떻게 사용할 수 있습니까? ) :

$.ajax({
    url: "http://127.0.0.1:5000/foo", 
    type: "POST",
    contentType: "application/json",
    data: JSON.stringify({'inputVar': 1}),
    success: function( data ) { 
        alert( "success" + data );
    }   
});

내가 얻을 Cross Origin Resource Sharing (CORS)오류 :

No 'Access-Control-Allow-Origin' header is present on the requested resource. 
Origin 'null' is therefore not allowed access. 
The response had HTTP status code 500.

다음 두 가지 방법으로 해결하려고했지만 작동하지 않는 것 같습니다.

  1. Flask-CORS 사용

이것은 cross-origin AJAX를 가능하게 Flask하는 처리 CORS위한 확장입니다 .

이 솔루션을 사용하는 pythonServer.py :

from flask import Flask
from flask.ext.cors import CORS, cross_origin

app = Flask(__name__)
cors = CORS(app, resources={r"/foo": {"origins": "*"}})
app.config['CORS_HEADERS'] = 'Content-Type'

@app.route('/foo', methods=['POST','OPTIONS'])
@cross_origin(origin='*',headers=['Content-Type','Authorization'])
def foo():
    return request.json['inputVar']

if __name__ == '__main__':
    app.run()
  1. 특정 플라스크 데코레이터 사용

이것은 장식하는 기능을 허용해야하는 장식자를 정의 하는 공식 Flask 코드 스 니펫 CORS입니다.

이 솔루션을 사용하는 pythonServer.py :

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

app = Flask(__name__)

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

@app.route('/foo', methods=['GET','POST','OPTIONS'])
@crossdomain(origin="*")
def foo():
    return request.json['inputVar']

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

그 이유를 알려주시겠습니까?


코드를 약간 수정 한 후 챔피언처럼 작동했습니다.

# initialization
app = Flask(__name__)
app.config['SECRET_KEY'] = 'the quick brown fox jumps over the lazy   dog'
app.config['CORS_HEADERS'] = 'Content-Type'

cors = CORS(app, resources={r"/foo": {"origins": "http://localhost:port"}})

@app.route('/foo', methods=['POST'])
@cross_origin(origin='localhost',headers=['Content- Type','Authorization'])
def foo():
    return request.json['inputVar']

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

*를 localhost로 대체했습니다. 많은 블로그와 게시물을 읽었으므로 특정 도메인에 대한 액세스를 허용해야합니다.


간단한 방법으로 결과를 얻을 수 있습니다.

@app.route('your route', methods=['GET'])
def yourMethod(params):
    response = flask.jsonify({'some': 'data'})
    response.headers.add('Access-Control-Allow-Origin', '*')
    return response

글쎄, 나는 같은 문제에 직면했다. 이 페이지를 방문 할 수있는 신규 사용자를 위해. 공식 문서를 따르십시오.

flask-cors 설치

pip install -U flask-cors

그런 다음 앱 초기화 후 flask-cors기본 인수로 초기화합니다 .

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

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

Access-Control-Allow-OriginFlask 응답 객체에 헤더 를 설정하는 것은 대부분의 경우 (이것처럼) 괜찮지 만 정적 자산을 제공 할 때는 영향을 미치지 않습니다 (최소한 프로덕션 설정에서). 정적 자산은 전면 웹 서버 (일반적으로 Nginx 또는 Apache)에서 직접 제공되기 때문입니다. 따라서이 경우 Flask가 아닌 웹 서버 수준에서 응답 헤더를 설정해야합니다.

자세한 내용 은 헤더를 설정하는 방법을 설명하는 잠시 전에 작성한이 기사를 참조하십시오 (제 경우에는 Font Awesome 자산의 도메인 간 서비스를 수행하려고했습니다).

Also, as @Satu said, you may need to allow access only for a specific domain, in the case of JS AJAX requests. For requesting static assets (like font files), I think the rules are less strict, and allowing access for any domain is more accepted.


Might as well make this an answer. I had the same issue today and it was more of a non-issue than expected. After adding the CORS functionality, you must restart your Flask server (ctrl + c -> python manage.py runserver, or whichever method you use)) in order for the change to take effect, even if the code is correct. Otherwise the CORS will not work in the active instance.

Here's how it looks like for me and it works (Python 3.6.1, Flask 0.12):

factory.py:

from flask import Flask
from flask_cors import CORS  # This is the magic


def create_app(register_stuffs=True):
    """Configure the app and views"""
    app = Flask(__name__)
    CORS(app)  # This makes the CORS feature cover all routes in the app

    if register_stuffs:
        register_views(app)
    return app


def register_views(app):
    """Setup the base routes for various features."""
    from backend.apps.api.views import ApiView
    ApiView.register(app, route_base="/api/v1.0/")

views.py:

from flask import jsonify
from flask_classy import FlaskView, route


class ApiView(FlaskView):
    @route("/", methods=["GET"])
    def index(self):
        return "API v1.0"

    @route("/stuff", methods=["GET", "POST"])
    def news(self):
        return jsonify({
            "stuff": "Here be stuff"
        })

In my React app console.log:

Sending request:
GET /stuff
With parameters:
null
bundle.js:17316 Received data from Api:
{"stuff": "Here be stuff"}

I used decorator given by Armin Ronacher with little modifications (due to different headers that are requested by the client).And that worked for me. (where I use angular as the requester requesting application/json type).

The code is slightly modified at below places,

from flask import jsonify

@app.route('/my_service', methods=['POST', 'GET','OPTIONS'])
@crossdomain(origin='*',headers=['access-control-allow-origin','Content-Type'])
def my_service():
    return jsonify(foo='cross domain ftw')

jsonify will send a application/json type, else it will be text/html. headers are added as the client in my case request for those headers

 const httpOptions = {
      headers: new HttpHeaders({
        'Content-Type': 'application/json',
        'Access-Control-Allow-Origin':'*'
      })
    };
    return this.http.post<any>(url, item,httpOptions)

I struggled a lot with something similar. Try the following:

  1. Use some sort of browser plugin which can display the HTML headers.
  2. Enter the URL to your service, and view the returned header values.
  3. Make sure Access-Control-Allow-Origin is set to one and only one domain, which should be the request origin. Do not set Access-Control-Allow-Origin to *.

If this doesn't help, take a look at this article. It's on PHP, but it describes exactly which headers must be set to which values for CORS to work.

CORS That Works In IE, Firefox, Chrome And Safari


Note: The placement of cross_origin should be right and dependencies are installed. On the client side, ensure to specify kind of data server is consuming. For example application/json or text/html

For me the code written below did magic

from flask import Flask,request,jsonify
from flask_cors import CORS,cross_origin
app=Flask(__name__)
CORS(app, support_credentials=True)
@app.route('/api/test', methods=['POST', 'GET','OPTIONS'])
@cross_origin(supports_credentials=True)
def index():
    if(request.method=='POST'):
     some_json=request.get_json()
     return jsonify({"key":some_json})
    else:
        return jsonify({"GET":"GET"})


if __name__=="__main__":
    app.run(host='0.0.0.0', port=5000)

ReferenceURL : https://stackoverflow.com/questions/26980713/solve-cross-origin-resource-sharing-with-flask

반응형