How to enable CORS in flask

I am trying to make a cross origin request using jquery but it keeps being reject with the message

XMLHttpRequest cannot load No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin ... is therefore not allowed access.

I am using flask, heroku, and jquery

the client code looks like this:

$(document).ready(function() { $('#submit_contact').click(function(e){ e.preventDefault(); $.ajax({ type: 'POST', url: ' // 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); } }); }); }); 

on the heroku side i am using flask and it is like this

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() 

10 Answers

Here is what worked for me when I deployed to Heroku.


Install flask-cors by running - pip install -U flask-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!" 
8

I've just faced the same issue and I came to believe that the other answers are a bit more complicated than they need to be, so here's my approach for those who don't want to rely on more libraries or decorators:

A CORS request actually consists of two HTTP requests. A preflight request and then an actual request that is only made if the preflight passes successfully.

The preflight request

Before the actual cross domain POST request, the browser will issue an OPTIONS request. This response should not return any body, but only some reassuring headers telling the browser that it's alright to do this cross-domain request and it's not part of some cross site scripting attack.

I wrote a Python function to build this response using the make_response function from the flask module.

def _build_cors_preflight_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 

This response is a wildcard one that works for all requests. If you want the additional security gained by CORS, you have to provide a whitelist of origins, headers and methods.

This response will convince your (Chrome) browser to go ahead and do the actual request.

The actual request

When serving the actual request you have to add one CORS header - otherwise the browser won't return the response to the invoking JavaScript code. Instead the request will fail on the client-side. Example with jsonify

response = jsonify({"order_id": 123, "status": "shipped"} response.headers.add("Access-Control-Allow-Origin", "*") return response 

I also wrote a function for that.

def _corsify_actual_response(response): response.headers.add("Access-Control-Allow-Origin", "*") return response 

allowing you to return a one-liner.

Final code

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_preflight_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_preflight_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 
9

OK, I don't think the official snippet mentioned by galuszkak should be used everywhere, we should concern the case that some bug may be triggered during the handler such as hello_world function. Whether the response is correct or uncorrect, the Access-Control-Allow-Origin header is what we should concern. So, it is very simple, just like the snippet bellow:

# define your bluprint from flask import Blueprint blueprint = Blueprint('blueprint', __name__) # put this sippet ahead of all your bluprints # blueprint can also be app~~ @blueprint.after_request def after_request(response): header = response.headers header['Access-Control-Allow-Origin'] = '*' # Other headers can be added here if needed return response # write your own blueprints with business logics @blueprint.route('/test', methods=['GET']) def test(): return "test success" 

That is all~~

2

If you want to enable CORS for all routes, then just install flask_cors extension (pip3 install -U flask_cors) and wrap app like this: CORS(app).

That is enough to do it (I tested this with a POST request to upload an image, and it worked for me):

from flask import Flask from flask_cors import CORS app = Flask(__name__) CORS(app) # This will enable CORS for all routes 

Important note: if there is an error in your route, let us say you try to print a variable that does not exist, you will get a CORS error related message which, in fact, has nothing to do with CORS.

4

I resolved this same problem in python using flask and with this library. flask_cors in file init.py:

#pip install flask_cors from flask_cors import CORS app = Flask(__name__) CORS(app) cors = CORS(app, resource={ r"/*":{ "origins":"*" } }) 

and its all.

Reference:

4

Improving the solution described here:

With after_request we can handle the CORS response headers avoiding to add extra code to our 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 
5

Try the following decorators:

@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() 

This decorator would be created as follows:

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 

You can also check out this package Flask-CORS

1

All the responses above work okay, but you'll still probably get a CORS error, if the application throws an error you are not handling, like a key-error, if you aren't doing input validation properly, for example. You could add an error handler to catch all instances of exceptions and add CORS response headers in the server response

So define an error handler - 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 

then using Billal's answer:

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 

My solution is a wrapper around 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(): ... 

If you can't find your problem and you're code should work, it may be that your request is just reaching the maximum of time heroku allows you to make a request. Heroku cancels requests if it takes more than 30 seconds.

Reference:

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like