用烧瓶解决跨产地资源共享问题

以下为 Flask(我如何使用数据从 Ajax 发布在烧瓶?)的 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. 使用烧瓶-CORS

这是一个用于处理 CORSFlask扩展,它使得跨原点 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 代码片段,定义了一个装饰器,它应该允许 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()

你能解释一下为什么吗?

252932 次浏览

我也曾为类似的事情挣扎过。试试下面的方法:

  1. 使用某种浏览器插件可以显示 HTML 标题。
  2. 输入服务的 URL,并查看返回的头部值。
  3. 确保 Access-Control-allow-Origin 设置为一个且仅为一个域,该域应该是请求源。不要将访问控制-允许-起源设置为 * 。

如果这没有帮助,看看这篇文章。它是在 PHP 上编写的,但它确切地描述了 CORS 必须将哪些头设置为哪些值才能工作。

适用于 IE,Firefox,Chrome 和 Safari 的 CORS

在对代码稍作修改之后,它工作得非常出色

# 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 替换了 * 。因为我在许多博客和文章中读到,你应该允许访问特定的域

请注意,在 Flask 响应对象中设置 Access-Control-Allow-Origin头在许多情况下是可行的(比如这个) ,但是在服务静态资产时(至少在生产设置中)没有效果。这是因为静态资产直接由前端 Web 服务器(通常是 Nginx 或 Apache)提供。因此,在这种情况下,您必须在 Web 服务器级别设置响应头,而不是在 Flask 中。

有关更多细节,请参阅我不久前撰写的这篇文章 解释如何设置标题(在我的案例中,我试图为 Font Awesome 资产提供跨域服务)。

另外,如@Satu 所说,您可能需要仅允许对特定域的访问,如果是 JS AJAX 请求。对于请求静态资产(比如字体文件) ,我认为规则没有那么严格,允许访问任何域更容易被接受。

你可以通过一个简单的方法得到结果:

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

还不如把这当成一个答案。我今天也遇到了同样的问题,而且比预期的更像是一个无关紧要的问题。在添加 CORS 功能之后,即使代码是正确的,您也需要 必须的重新启动 Flask 服务器(ctrl + c-> python manage.py runserver,或者您使用的任何方法) ,以使更改生效。否则 CORS 将无法在活动实例中工作。

下面是它的工作原理(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/")

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"}

嗯,我面临着同样的问题。对于新用户谁可能登陆这个网页。 跟着他们的官方文件走就行了。

安装烧瓶

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

我使用的 阿明 · 罗纳赫设计的装饰品只做了很少的修改(由于客户机请求的标头不同)。这招对我很管用。(其中我使用 angle 作为请求应用程序/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 _ source 的位置应该是正确的,并且已经安装了依赖项。 在客户端,确保指定使用的数据服务器类型,例如 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)

这个问题已经很老套了,但是我想我可以提供一个我认为是最简单的解决方案:

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

我认为问题出在飞行前的请求上。 似乎没有有效的方法来禁用自动答复的选项请求,如果你使用@path@put@patch@delete 装饰。 我的解决方案是在 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

我今天遇到了这个问题,没有一个答案对我有用。

我将 cross_origin()装饰器设置如下:

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

然后我做了:

  1. 在 IDE 中打开 FlaskPython 文件。
  2. 右键单击文件。
  3. 单击: 在终端运行 Python 文件

我的问题是用 CTRL+ALT+N运行 FlaskPython 文件。在 VSCode 中的“运行代码”按钮,我不应该那样运行 Flask 服务器。因此我认为 CORS 没有正确装载。

此外,我的 print()并不总是出现,因为这样,所以它也很难调试的东西。发生这种情况是因为通过 CTRL+ALT+N运行应用程序时,VSCode 关注的是 OUTPUT 窗口而不是 TERMINAL 窗口。

此外,是的出现在 OUTPUT 窗口中的 print()不像 TERMINAL 窗口那样支持表情符号。所以我的应用程序崩溃了很长一段时间直到我弄明白了一切。

虽然我犯了愚蠢的错误,但我应该更清楚。希望这能帮助到其他人!