Flask RESTful cross-domain issue with Angular: PUT, OPTIONS methods
Solution 1
I resolved the issue by rewriting my Flask backend to answer with an Access-Control-Allow-Origin header in my PUT response. Furthermore, I created an OPTIONS handler in my Flask app to answer the options method by following what I read in the http RFC.
The return on the PUT method looks like this:
return restful.request.form, 201, {'Access-Control-Allow-Origin': '*'}
My OPTIONS method handler looks like this:
def options (self):
return {'Allow' : 'PUT' }, 200, \
{ 'Access-Control-Allow-Origin': '*', \
'Access-Control-Allow-Methods' : 'PUT,GET' }
@tbicr is right: Flask DOES answer the OPTIONS method automatically for you. However, in my case it wasn't transmitting the Access-Control-Allow-Origin header with that answer, so my browser was getting a reply from the api that seemed to imply that cross-domain requests were not permitted. I overloaded the options request in my case and added the ACAO header, and the browser seemed to be satisfied with that, and followed up OPTIONS with a PUT that also worked.
Solution 2
With the Flask-CORS module, you can do cross-domain requests without changing your code.
from flask.ext.cors import CORS
app = Flask(__name__)
cors = CORS(app, resources={r"/api/*": {"origins": "*"}})
Update
As Eric suggested, the flask.ext.cors
module is now deprecated, you should rather use the following code:
from flask_cors import CORS
app = Flask(__name__)
cors = CORS(app, resources={r"/api/*": {"origins": "*"}})
Solution 3
You can use the after_request hook:
@app.after_request def after_request(response): response.headers.add('Access-Control-Allow-Origin', '*') response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization') response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE') return response
Solution 4
How about this workaround:
from flask import Flask
from flask.ext import restful
from flask.ext.restful import Api
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config.from_object('config')
#flask-sqlalchemy
db = SQLAlchemy(app)
#flask-restful
api = restful.Api(app)
@app.after_request
def after_request(response):
response.headers.add('Access-Control-Allow-Origin', '*')
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE')
return response
import views
I took this from this tutorial. Works very good. actually, i think this is the best approach I've seen so far.
Returning {'Access-Control-Allow-Origin': '*'}
on each endpoint, doesn't seems to be efficient since you have to add it on every endpoint. a bit anoying..., at least for me.
I tried @cors.crossdomain(origin='*')
but, looks like it only works with GET request.
Solution 5
You're right, OPTIONS
method called every time before real request in browser. OPTIONS
response have allowed methods and headers. Flask automatically process OPTIONS
requests.
To get access for cross domain request you API must have Access-Control-Allow-Origin
header. It can contain specific domains, but if you want allow requests from any domains you can set it to Access-Control-Allow-Origin: *
.
To set up CORS for flask
you can look at one extension code or try use this extension: https://github.com/wcdolphin/flask-cors/blob/master/flask_cors.py.
To set up CORS for flask-restful
look this pull requests: https://github.com/twilio/flask-restful/pull/122 and https://github.com/twilio/flask-restful/pull/131. But looks like flask-restful
does not support it by default yet.
Related videos on Youtube
rgb
Updated on July 09, 2022Comments
-
rgb almost 2 years
I've developed a small write-only REST api with Flask Restful that accepts PUT request from a handful of clients that can potentially have changing IP addresses. My clients are embedded Chromium clients running an AngularJS front-end; they authenticate with my API with a simple magic key -- it's sufficient for my very limited scale.
I'm testing deploying my API now and I notice that the Angular clients are attempting to send an OPTIONS http methods to my Flask service. My API meanwhile is replying with a 404 (since I didn't write an OPTIONS handler yet, only a PUT handler). It seems that when sending cross-domain requests that are not POST or GET, Angular will send a pre-flight OPTIONS method at the server to make sure the cross-domain request is accepted before it sends the actual request. Is that right?
Anyway, how do I allow all cross-domain PUT requests to Flask Restful API? I've used cross-domaion decorators with a (non-restful) Flask instance before, but do I need to write an OPTIONS handler as well into my API?
-
awzx almost 7 yearsThanks ! Works perfectly.
-
silentsudo over 4 yearsthis is partial answer, untill i added @app.after_request stackoverflow.com/questions/23741362/…
-
Mathieu Rodic over 4 yearsThe code above works as is. The link you provided shows a different solution to the same problem.
-
drysdam almost 3 yearsGolden answer. I get that Flask-CORS is simpler for some people, but on a locked-down system where you have to fill out paperwork to change directories, let alone software, these 7 lines save lives.