Jquery 如何在烧瓶中启用CORS
我试图使用jquery发出一个跨源请求,但它一直被消息拒绝 无法加载XMLHttpRequesthttp://... 没有“访问控制允许来源” 请求的资源上存在标头。起源。。。因此 不允许访问 我正在使用flask、heroku和jquery 客户端代码如下所示:Jquery 如何在烧瓶中启用CORS,jquery,python,heroku,flask,cors,Jquery,Python,Heroku,Flask,Cors,我试图使用jquery发出一个跨源请求,但它一直被消息拒绝 无法加载XMLHttpRequesthttp://... 没有“访问控制允许来源” 请求的资源上存在标头。起源。。。因此 不允许访问 我正在使用flask、heroku和jquery 客户端代码如下所示: $(document).ready(function() { $('#submit_contact').click(function(e){ e.preventDefault(); $.ajax
$(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);
}
});
});
});
在heroku这边,我用的是烧瓶,它是这样的
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()
请尝试以下装饰程序:
@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
您也可以查看此软件包以下是我部署到Heroku时的工作原理
通过运行安装烧瓶cors-
pip安装-U形烧瓶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提到的官方代码片段应该在任何地方都使用,我们应该关注在处理过程中可能会触发一些bug的情况,比如
hello\u world
函数。无论响应是正确的还是不正确的,accesscontrolalloworigin
头是我们应该关注的。所以,事情很简单,就像下面所说的:
@blueprint.after_request # blueprint can also be app~~
def after_request(response):
header = response.headers
header['Access-Control-Allow-Origin'] = '*'
return response
这就是全部~~我刚刚遇到了同样的问题,我开始相信其他答案比它们需要的要复杂一些,因此我的方法适用于那些不想依赖更多库或装饰器的人:
@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()
CORS请求实际上由两个HTTP请求组成。一个飞行前请求,然后是一个只有在飞行前成功通过时才发出的实际请求
飞行前的请求
在实际的跨域POST
请求之前,浏览器将发出OPTIONS
请求。此响应不应返回任何正文,只应返回一些令人放心的标题,告诉浏览器可以执行此跨域请求,并且它不是某些跨站点脚本攻击的一部分
我使用flask
模块中的make\u response
函数编写了一个Python函数来构建这个响应
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
允许您返回一个班轮
最终代码
如果您想为所有路由启用CORS,那么只需安装扩展(
pip3安装-U flask\U CORS
)并像这样包装app
:CORS(app)
这就足够了(我用一个上传图像的POST
请求测试了这一点,它对我有效):
重要提示:如果路由中有错误,假设您试图打印一个不存在的变量,您将收到一条与CORS错误相关的消息,事实上,该消息与CORS无关。我的解决方案是围绕应用程序的包装。路由:
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():
...
上面的所有响应都可以正常工作,但是如果应用程序抛出一个您没有处理的错误(例如,如果您没有正确执行输入验证),您仍然可能会得到一个CORS错误。您可以添加一个错误处理程序来捕获所有异常实例,并在服务器响应中添加CORS响应头 因此,请定义一个错误处理程序-errors.py:
from flask import json, make_response, jsonify
from werkzeug.exceptions import HTTPException
# define an error handling function
def init_handler(app):
# catch every type of exception
@app.errorhandler(Exception)
def handle_exception(e):
#loggit()!
# return json response of error
if isinstance(e, HTTPException):
response = e.get_response()
# replace the body with JSON
response.data = json.dumps({
"code": e.code,
"name": e.name,
"description": e.description,
})
else:
# build response
response = make_response(jsonify({"message": 'Something went wrong'}), 500)
# add the CORS header
response.headers['Access-Control-Allow-Origin'] = '*'
response.content_type = "application/json"
return response
然后使用答案:
如果您找不到问题,并且您的代码应该可以工作,那么可能是您的请求刚刚达到heroku允许您发出请求的最长时间。如果超过30秒,Heroku将取消请求
参考资料:我使用flask和这个库在python中解决了同样的问题。 flask_cors 在文件init.py中: 就这些
参考:改进此处描述的解决方案: 使用
after_request
我们可以处理CORS响应头,避免向端点添加额外代码:
### 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
仍然不起作用。我已经试过了,我也用过Flask CORS软件包。我认为Flask CORS是在这个基础上为hello cross origin world构建的!这是唯一对我有效的解决办法。谢谢你是救世主!工作得很有魅力。嗨!你能帮我弄清楚我的情况吗?我使用Python/Flask编写了一个简单的API,甚至没有它的视图。我通过
curl
命令到达它。现在,我编写了一个简短的html页面,并尝试使用JS fetch()方法向基于Heroku的API发出请求,我发现了CORS错误。在我应用了您的代码之后,我的终端开始用HTML代码(HTTP/1.1503服务不可用)而不是JSON响应我。这里可能有什么错误?非常感谢。在任何人将此代码复制到他们的应用程序之前,请,因为只需要其中的一些行。谢谢@Niels B。太多了,你节省了我的时间。我以前添加过cors配置,但没有正确设置。这是目前为止关于烧瓶上cors问题的最佳答案。工作得很有魅力!感谢@nielthank您的详细解释!!这很有帮助!使用许多解决方案,包括CORS和您的解决方案,但它们都不适用于aws(遵循此示例-),有人知道发生了什么吗?此解决方案非常简单但优雅!谢谢,你真的节省了我的时间。这也帮助我完成了一个带有基本CRUD操作的小项目。不需要任何花哨的东西,只要绕过错误:)谢谢!这个简单而通用的解决方案允许我从React web代码调用API,不再需要CORS块。谢谢!重要的笔记部分节省了我很多时间。谢谢!您的便条是金色的。虽然此链接可以回答问题,但最好在此处包含答案的基本部分,并提供链接以供参考。
from flask import Flask
from flask_cors import CORS
# import error handling file from where you have defined it
from . import errors
app = Flask(__name__)
CORS(app) # This will enable CORS for all routes
errors.init_handler(app) # initialise error handling
#pip install flask_cors
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
cors = CORS(app, resource={
r"/*":{
"origins":"*"
}
})
### 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