Estou tentando fazer uma solicitação de origem cruzada usando jquery, mas continua sendo rejeitada com a mensagem
XMLHttpRequest não pode carregar http: // ... Nenhum cabeçalho 'Access-Control-Allow-Origin' está presente no recurso solicitado. Origem ... portanto, não é permitido o acesso.
Estou usando flask, heroku e jquery
o código do cliente é parecido com este:
$(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);
}
});
});
});
do lado do heroku estou usando o frasco e é assim
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()
curl
comandos. Agora eu escrevi uma página html curta e tentando fazer uma solicitação com o método JS fetch () para minha API que baseado em Heroku e eu tenho o erro CORS. Depois de aplicar seu código, meu terminal começou a responder para mim com o código HTML (HTTP / 1.1 503 Serviço indisponível) em vez do JSON. O que pode ser um erro aqui? Obrigado!!OK, não acho que o trecho oficial mencionado por galuszkak deva ser usado em todos os lugares, devemos nos preocupar com o caso de que algum bug possa ser acionado durante o manipulador, como a
hello_world
função. Quer a resposta esteja correta ou incorreta, oAccess-Control-Allow-Origin
cabeçalho é o que devemos nos preocupar. Então, a coisa é muito simples, assim como a seguir:@blueprint.after_request # blueprint can also be app~~ def after_request(response): header = response.headers header['Access-Control-Allow-Origin'] = '*' return response
Isso é tudo ~~
fonte
Acabei de enfrentar o mesmo problema e passei a acreditar que as outras respostas são um pouco mais complicadas do que precisam ser, então aqui está minha abordagem para aqueles que não querem depender de mais bibliotecas ou decoradores:
Na verdade, uma solicitação CORS consiste em duas solicitações HTTP. Uma solicitação de comprovação e, em seguida, uma solicitação real que só é feita se a comprovação for aprovada com êxito.
O pedido de comprovação
Antes da
POST
solicitação real de vários domínios , o navegador emitirá umaOPTIONS
solicitação. Essa resposta não deve retornar nenhum corpo, mas apenas alguns cabeçalhos tranquilizadores informando ao navegador que não há problema em fazer essa solicitação entre domínios e não faz parte de nenhum ataque de script entre sites.Escrevi uma função Python para construir essa resposta usando a
make_response
função doflask
módulo.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
Essa resposta é um caractere curinga que funciona para todas as solicitações. Se você deseja a segurança adicional obtida pelo CORS, deve fornecer uma lista de permissões de origens, cabeçalhos e métodos.
Esta resposta convencerá seu navegador (Chrome) a prosseguir e fazer a solicitação real.
O pedido real
Ao atender a solicitação real, você deve adicionar um cabeçalho CORS - caso contrário, o navegador não retornará a resposta ao código JavaScript de chamada. Em vez disso, a solicitação falhará no lado do cliente. Exemplo com jsonify
response = jsonify({"order_id": 123, "status": "shipped"} response.headers.add("Access-Control-Allow-Origin", "*") return response
Eu também escrevi uma função para isso.
def _corsify_actual_response(response): response.headers.add("Access-Control-Allow-Origin", "*") return response
permitindo que você retorne um one-liner.
Código final
from flask import Flask, request, jsonify, make_response from models import OrderModel flask_app = Flask(__name__) @flask_app.route("/api/orders", methods=["POST", "OPTIONS"]) def api_create_order(): if request.method == "OPTIONS": # CORS preflight return _build_cors_prelight_response() elif request.method == "POST": # The actual request following the preflight order = OrderModel.create(...) # Whatever. return _corsify_actual_response(jsonify(order.to_dict())) else raise RuntimeError("Weird - don't know how to handle method {}".format(request.method)) 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 def _corsify_actual_response(response): response.headers.add("Access-Control-Allow-Origin", "*") return response
fonte
Se você deseja ativar o CORS em todas as rotas, em seguida, basta instalar flask_cors extensão (
pip3 install -U flask_cors
) e enroleapp
como este:CORS(app)
.Isso é o suficiente para fazer isso (eu testei isso com uma
POST
solicitação para fazer upload de uma imagem e funcionou para mim):from flask import Flask from flask_cors import CORS app = Flask(__name__) CORS(app) # This will enable CORS for all routes
Nota importante: se houver um erro em sua rota, digamos que você tente imprimir uma variável que não existe, você receberá uma mensagem relacionada ao erro CORS que, na verdade, não tem nada a ver com CORS.
fonte
Experimente os seguintes decoradores:
@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()
Este decorador seria criado da seguinte maneira:
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
Você também pode verificar este pacote Flask-CORS
fonte
Melhorando a solução descrita aqui: https://stackoverflow.com/a/52875875/10299604
Com
after_request
, podemos lidar com os cabeçalhos de resposta CORS evitando adicionar código extra aos nossos endpoints:### 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
fonte
Minha solução é um wrapper em torno de app.route:
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(): ...
fonte
Todas as respostas acima funcionam bem, mas você provavelmente ainda obterá um erro CORS, se o aplicativo lançar um erro que você não está tratando, como um erro de chave, se você não estiver fazendo a validação de entrada corretamente, por exemplo. Você pode adicionar um manipulador de erros para capturar todas as instâncias de exceções e adicionar cabeçalhos de resposta CORS na resposta do servidor
Portanto, defina um gerenciador de erros - 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
então usando a resposta de Billal :
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
fonte
Resolvi esse mesmo problema em python usando flask e com essa biblioteca. flask_cors
Referência: https://flask-cors.readthedocs.io/en/latest/
fonte
Se você não consegue encontrar seu problema e seu código deve funcionar, pode ser que sua solicitação esteja atingindo o máximo de tempo que o heroku permite que você faça uma solicitação. O Heroku cancela solicitações se demorar mais de 30 segundos.
Referência: https://devcenter.heroku.com/articles/request-timeout
fonte