[英]Solve Cross Origin Resource Sharing with Flask
對於以下ajax
對Flask
的發布請求( 我如何在 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.
我嘗試通過以下兩種方式解決它,但似乎都沒有用。
這是一個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()
這是一個官方的 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
我在類似的事情上掙扎了很多。 請嘗試以下操作:
如果這沒有幫助,請查看這篇文章。 它在 PHP 上,但它准確地描述了必須將哪些標頭設置為哪些值才能使 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():
然后我做了:
我的問題是使用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.