Closed marzetas closed 1 year ago
Wow I just spent 3h debugging why the behavior of using CORS
was different from using cross_origin
... this is exactly the same issue.
I'll try to dig a bit into the source code for a fix.
I was not able to reproduce this. I ran the following...
"""
Flask-Cors example
===================
This is a tiny Flask Application demonstrating Flask-Cors, making it simple
to add cross origin support to your flask app!
:copyright: (c) 2016 by Cory Dolphin.
:license: MIT/X11, see LICENSE for more details.
"""
from flask import Flask, jsonify
import logging
try:
# The typical way to import flask-cors
from flask_cors import cross_origin
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_cors import cross_origin
app = Flask('FlaskCorsViewBasedExample')
logging.basicConfig(level=logging.INFO)
@app.route("/", methods=['GET'])
@cross_origin()
def helloWorld():
'''
This view has CORS enabled for all domains, representing the simplest
configuration of view-based decoration. The expected result is as
follows:
$ curl --include -X GET http://127.0.0.1:5000/ \
--header Origin:www.examplesite.com
>> HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 184
Access-Control-Allow-Origin: *
Server: Werkzeug/0.9.6 Python/2.7.9
Date: Sat, 31 Jan 2015 22:29:56 GMT
<h1>Hello CORS!</h1> Read about my spec at the
<a href="http://www.w3.org/TR/cors/">W3</a> Or, checkout my documentation
on <a href="https://github.com/corydolphin/flask-cors">Github</a>
'''
return '''<h1>Hello CORS!</h1> Read about my spec at the
<a href="http://www.w3.org/TR/cors/">W3</a> Or, checkout my documentation
on <a href="https://github.com/corydolphin/flask-cors">Github</a>'''
@app.route("/api/v1/users/create", methods=['GET', 'POST'])
@cross_origin(allow_headers=['Content-Type'])
def cross_origin_json_post():
'''
This view has CORS enabled for all domains, and allows browsers
to send the Content-Type header, allowing cross domain AJAX POST
requests.
Browsers will first make a preflight request to verify that the resource
allows cross-origin POSTs with a JSON Content-Type, which can be simulated
as:
$ curl --include -X OPTIONS http://127.0.0.1:5000/api/v1/users/create \
--header Access-Control-Request-Method:POST \
--header Access-Control-Request-Headers:Content-Type \
--header Origin:www.examplesite.com
>> HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Allow: POST, OPTIONS
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT
Content-Length: 0
Server: Werkzeug/0.9.6 Python/2.7.9
Date: Sat, 31 Jan 2015 22:25:22 GMT
$ curl --include -X POST http://127.0.0.1:5000/api/v1/users/create \
--header Content-Type:application/json \
--header Origin:www.examplesite.com
>> HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 21
Access-Control-Allow-Origin: *
Server: Werkzeug/0.9.6 Python/2.7.9
Date: Sat, 31 Jan 2015 22:25:04 GMT
{
"success": true
}
'''
return jsonify(success=True)
@app.route("/foo", methods=['POST'])
@cross_origin()
def create_item():
return 'bar'
@app.route("/foo", methods=['GET'])
def get_item():
return 'foo'
if __name__ == "__main__":
app.run(debug=True)
(flask-cors-new) ➜ flask-cors git:(switch-to-gha) ✗ curl --include -X GET http://127.0.0.1:5000/foo \
--header Origin:www.examplesite.com
HTTP/1.1 200 OK
Server: Werkzeug/2.3.6 Python/3.11.3
Date: Mon, 26 Jun 2023 05:44:15 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 3
Connection: close
foo%
(flask-cors-new) ➜ flask-cors git:(switch-to-gha) ✗ curl --include -X POST http://127.0.0.1:5000/foo \
--header Origin:www.examplesite.com
HTTP/1.1 200 OK
Server: Werkzeug/2.3.6 Python/3.11.3
Date: Mon, 26 Jun 2023 05:44:19 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 3
Access-Control-Allow-Origin: www.examplesite.com
Vary: Origin
Connection: close
Sorry @corydolphin but this problem persists with flask-cors 4.0.0 and Flask 3.0.0.
The curl I run to mimick my browser is
curl 'http://localhost:5000/graphql' -X OPTIONS -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/119.0' -H 'Accept: */*' -H 'Accept-Language: en-US,en;q=0.5' -H 'Accept-Encoding: gzip, deflate, br' -H 'Access-Control-Request-Method: POST' -H 'Access-Control-Request-Headers: content-type' -H 'Referer: http://localhost:5173/' -H 'Origin: http://localhost:5173' -H 'Connection: keep-alive' -H 'Sec-Fetch-Dest: empty' -H 'Sec-Fetch-Mode: cors' -H 'Sec-Fetch-Site: same-site' -H 'Pragma: no-cache' -H 'Cache-Control: no-cache' --verbose
I start the following flask app with flask --debug --app example.py run
:
from flask import Flask, jsonify
from flask_cors import cross_origin
app = Flask(__name__)
@app.route("/graphql", methods=["GET"])
def playground():
return jsonify("test"), 200
@app.route("/graphql", methods=["POST"])
@cross_origin(
origins=["http://localhost:5173"],
methods=["POST"],
allow_headers="*",
)
def server():
return jsonify("serving"), 200
With the version above, the curl command returns
< HTTP/1.1 200 OK
< Server: Werkzeug/3.0.0 Python/3.10.9
< Date: Tue, 31 Oct 2023 17:57:52 GMT
< Content-Type: text/html; charset=utf-8
< Allow: POST, HEAD, GET, OPTIONS
< Content-Length: 0
< Connection: close
When I swap the blocks such that the GET handler is last, the response correctly contains the access-control-allow-*
headers:
< HTTP/1.1 200 OK
< Server: Werkzeug/3.0.0 Python/3.10.9
< Date: Tue, 31 Oct 2023 17:59:31 GMT
< Content-Type: text/html; charset=utf-8
< Allow: POST, OPTIONS, GET, HEAD
< Access-Control-Allow-Origin: http://localhost:5173
< Access-Control-Allow-Headers: content-type
< Access-Control-Allow-Methods: POST
< Content-Length: 0
< Connection: close
I just used your example from June again. The error happens as described when the app routes are defined like below, with the non-cross_origin
-decorated route first.
from flask import Flask
import logging
from flask_cors import cross_origin
app = Flask("FlaskCorsViewBasedExample")
logging.basicConfig(level=logging.INFO)
@app.route("/foo", methods=["GET"])
def get_item():
return "foo"
@app.route("/foo", methods=["POST"])
@cross_origin()
def create_item():
return "bar"
if __name__ == "__main__":
app.run(debug=True)
Hi, I was wondering if you could help with an issue I'm observing while using the
cross_origin
decorator. I have two endpoints linked to the same route, one serving GET requests, the other serving POST requests. Something like this:What happens here is that the
cross_origin
decorator is never hit when I hit the POST endpoint.From what I can see, it seems like the decorator is linked to the route, and only the first route declared keeps the
cross_origin
decorator. I'm saying this because altering the order of the declaration of the endpoints makes the POST one to fire the cross origin decorator. Basically this works:Any ideas? The code works in this second iteration, but it's not ideal that the order of the declarations of the endpoints affects the cross origin decorator.
Thanks in advance!