Я пытаюсь сделать запрос с перекрестным происхождением с помощью jquery, но он продолжает отклоняться с сообщением
XMLHttpRequest не может загрузить http: // ... На запрошенном ресурсе отсутствует заголовок «Access-Control-Allow-Origin». Origin ... поэтому не имеет доступа.
Я использую flask, heroku и jquery
код клиента выглядит так:
$(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);
}
});
});
});
на стороне героку я использую колбу, и это примерно так
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
командами. Теперь я написал короткую html-страницу и пытаюсь сделать запрос с помощью метода JS fetch () к моему API, который основан на Heroku, и у меня есть ошибка CORS. После того, как я применил ваш код, мой терминал начал отвечать мне кодом HTML (HTTP / 1.1 503 Service Unavailable) вместо JSON. В чем тут может быть ошибка? Спасибо!!Хорошо, я не думаю, что официальный фрагмент, упомянутый galuszkak, следует использовать повсюду, мы должны учитывать случай, когда во время обработки может быть вызвана какая-то ошибка, такая как
hello_world
функция. Независимо от того, верен ли ответ или нет,Access-Control-Allow-Origin
мы должны беспокоиться о заголовке. Итак, все очень просто, как показано ниже:@blueprint.after_request # blueprint can also be app~~ def after_request(response): header = response.headers header['Access-Control-Allow-Origin'] = '*' return response
Это все ~~
источник
Я только что столкнулся с той же проблемой, и я пришел к выводу, что другие ответы немного сложнее, чем они должны быть, поэтому вот мой подход для тех, кто не хочет полагаться на дополнительные библиотеки или декораторы:
Запрос CORS фактически состоит из двух HTTP-запросов. Предварительный запрос, а затем фактический запрос, который выполняется только в том случае, если предварительная проверка проходит успешно.
Предполетный запрос
Перед фактическим междоменным
POST
запросом браузер выдастOPTIONS
запрос. Этот ответ не должен возвращать никакого тела, а только некоторые обнадеживающие заголовки, сообщающие браузеру, что это нормально выполнять этот междоменный запрос и что он не является частью какой-либо атаки межсайтового скриптинга.Я написал функцию Python для создания этого ответа, используя
make_response
функцию изflask
модуля.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
позволяя вам вернуть однострочный.
Окончательный код
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
источник
Если вы хотите включить CORS для всех маршрутов, а затем просто установить flask_cors расширение (
pip3 install -U flask_cors
) и обертку ,app
как это:CORS(app)
.Для этого достаточно (я тестировал это с
POST
запросом на загрузку изображения, у меня это сработало):from flask import Flask from flask_cors import CORS app = Flask(__name__) CORS(app) # This will enable CORS for all routes
Важное примечание: если в вашем маршруте есть ошибка, допустим, вы пытаетесь распечатать несуществующую переменную, вы получите сообщение об ошибке CORS, которое на самом деле не имеет ничего общего с CORS.
источник
Попробуйте следующие декораторы:
@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
Вы также можете ознакомиться с этим пакетом Flask-CORS
источник
Мое решение - оболочка вокруг 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(): ...
источник
Улучшение решения, описанного здесь: https://stackoverflow.com/a/52875875/10299604
С помощью
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
источник
Все приведенные выше ответы работают нормально, но вы все равно, вероятно, получите ошибку 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
затем используя ответ Биллала :
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
источник
Если вы не можете найти свою проблему и ваш код должен работать, возможно, ваш запрос просто достигает максимального времени, которое heroku позволяет вам сделать. Heroku отменяет запросы, если это занимает более 30 секунд.
Ссылка: https://devcenter.heroku.com/articles/request-timeout
источник
Я решил эту же проблему в python, используя колбу и эту библиотеку. flask_cors
Ссылка: https://flask-cors.readthedocs.io/en/latest/
источник