簡體   English   中英

用Flask解決跨源資源共享

[英]Solve Cross Origin Resource Sharing with Flask

對於以下ajaxFlask的發布請求( 我如何在 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

這是一個Flask擴展,用於處理CORS ,應該使跨域 AJAX 成為可能。

我的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 裝飾器

這是一個官方的 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()

你能說明為什么會這樣嗎?

您可以通過簡單的方式獲得結果:

@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!"

在對您的代碼進行一些修改后,它就像一個冠軍

# 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 替換了 *。 正如我在許多博客和帖子中所讀到的那樣,您應該允許訪問特定域

不妨把這個作為一個答案。 我今天遇到了同樣的問題,它比預期的更不是問題。 添加 CORS 功能后,您必須重新啟動 Flask 服務器( ctrl + c -> python manage.py runserver ,或您使用的任何方法))以使更改生效,即使代碼正確。 否則 CORS 將無法在活動實例中工作。

這是對我來說的樣子和它的工作原理(Python 3.6.1,Flask 0.12):

工廠.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/")

視圖.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"
        })

在我的 React 應用程序 console.log 中:

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

請注意,在 Flask 響應對象中設置Access-Control-Allow-Origin標頭在許多情況下都很好(例如這種情況),但在提供靜態資產時(至少在生產設置中)沒有任何影響。 這是因為靜態資產直接由前端 Web 服務器(通常是 Nginx 或 Apache)提供服務。 因此,在這種情況下,您必須在 Web 服務器級別而不是在 Flask 中設置響應標頭。

有關更多詳細信息,請參閱我不久前寫的這篇文章,其中解釋了如何設置標題(在我的例子中,我試圖對 Font Awesome 資產進行跨域服務)。

此外,正如@Satu 所說,在 JS AJAX 請求的情況下,您可能只需要允許訪問特定域。 對於請求靜態資產(如字體文件),我認為規則不那么嚴格,並且更容易接受允許訪問任何域。

我使用了 Armin Ronacher提供的裝飾器,稍作修改(由於客戶端請求的標頭不同)。這對我有用。 (我使用 angular 作為請求應用程序/json 類型的請求者)。

代碼在以下地方略有修改,

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 將發送一個 application/json 類型,否則它將是 text/html。 在我對這些標頭的請求中,標頭被添加為客戶端

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

注意:cross_origin 的位置應該是對的,並且已經安裝了依賴。 在客戶端,確保指定服務器正在消耗的數據類型。 例如 application/json 或 text/html

對我來說,下面寫的代碼很神奇

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)

我可能在這個問題上遲到了,但下面的步驟解決了這個問題

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

我認為問題出在預檢請求上。 如果您使用 @route @put @patch @delete 裝飾器,似乎沒有有效的方法來禁用對 OPTIONS 請求的自動回答。 我的解決方法是 api 開頭的以下代碼片段(在任何修飾函數之前)

def option_todo(id): 
  return '', 204 
 
app.add_url_rule('/', view_func=option_todo, provide_automatic_options=False, methods=['OPTIONS']) 
app.add_url_rule(r'/<path:path>', view_func=option_todo, provide_automatic_options=False, methods=['OPTIONS']) 

@app.after_request
def after_request(response):
  response.headers['Access-Control-Allow-Methods']='*'
  response.headers['Access-Control-Allow-Origin']='*'
  response.headers['Vary']='Origin'
  return response

我在類似的事情上掙扎了很多。 請嘗試以下操作:

  1. 使用某種可以顯示 HTML 標題的瀏覽器插件。
  2. 輸入您的服務的 URL,並查看返回的標頭值。
  3. 確保 Access-Control-Allow-Origin 設置為一個且只有一個域,該域應該是請求源。 不要將 Access-Control-Allow-Origin 設置為 *。

如果這沒有幫助,請查看這篇文章。 它在 PHP 上,但它准確地描述了必須將哪些標頭設置為哪些值才能使 CORS 工作。

適用於 IE、Firefox、Chrome 和 Safari 的 CORS

這已經是一個非常古老且覆蓋面很廣的問題,但我想我會貢獻我認為最簡單的解決方案:

@app.after_request
def after_request(response: Response) -> Response:
    response.access_control_allow_origin = "*"
    return response

我今天遇到了這個問題,沒有一個答案對我有用。

我將cross_origin()裝飾器設置如下:

@app.route('/', methods = ['POST'])
@cross_origin()
def index():

然后我做了:

  1. 在 IDE 中打開 Flask Python 文件。
  2. 用鼠標右鍵單擊該文件。
  3. 單擊:在終端中運行 Python 文件

我的問題是使用CTRL+ALT+N運行 Flask Python 文件。 VSCode 中的“運行代碼”按鈕,我不應該那樣運行 Flask 服務器。 因此,我認為 CORS 沒有正確加載。

此外,我的print()並不總是出現,因此也很難調試東西。 發生這種情況是因為通過CTRL+ALT+N運行應用程序,VSCode 將焦點放在 OUTPUT 窗口而不是 TERMINAL 窗口。

此外,出現在 OUTPUT 窗口中的print() s不像TERMINAL 窗口那樣支持表情符號。 所以我的應用程序崩潰了最長的時間,直到我弄清楚了。

不過,我犯了一個愚蠢的錯誤,應該更清楚。 希望這對其他人有幫助!

我的問題是預檢問題,但我必須添加到app.py

...

@app.after_request
def after_request(response: Response) -> Response:
    response.access_control_allow_credentials = True
    return response

我的修復是

@app.after_request
def handle_options(response):
    response.headers["Access-Control-Allow-Origin"] = "*"
    response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS"
    response.headers["Access-Control-Allow-Headers"] = "Content-Type, X-Requested-With"

    return response

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM