Solve Cross Origin Resource Sharing with Flask - javascript

For the following ajax post request for Flask (how can I use data posted from ajax in flask?):
$.ajax({
url: "http://127.0.0.1:5000/foo",
type: "POST",
contentType: "application/json",
data: JSON.stringify({'inputVar': 1}),
success: function( data ) {
alert( "success" + data );
}
});
I get a Cross Origin Resource Sharing (CORS) error:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'null' is therefore not allowed access.
The response had HTTP status code 500.
I tried solving it in the two following ways, but none seems to work.
Using Flask-CORS
This is a Flask extension for handling CORS that should make cross-origin AJAX possible.
http://flask-cors.readthedocs.org/en/latest/
How to enable CORS in flask and heroku
Flask-cors wrapper not working when jwt auth wrapper is applied.
Javascript - No 'Access-Control-Allow-Origin' header is present on the requested resource
My pythonServer.py using this solution:
from flask import Flask
from flask.ext.cors import CORS, cross_origin
app = Flask(__name__)
cors = CORS(app, resources={r"/foo": {"origins": "*"}})
app.config['CORS_HEADERS'] = 'Content-Type'
#app.route('/foo', methods=['POST','OPTIONS'])
#cross_origin(origin='*',headers=['Content-Type','Authorization'])
def foo():
return request.json['inputVar']
if __name__ == '__main__':
app.run()
Using specific Flask Decorator
This is an official Flask code snippet defining a decorator that should allow CORS on the functions it decorates.
http://flask.pocoo.org/snippets/56/
Python Flask cross site HTTP POST - doesn't work for specific allowed origins
http://chopapp.com/#351l7gc3
My pythonServer.py using this solution:
from flask import Flask, make_response, request, current_app
from datetime import timedelta
from functools import update_wrapper
app = Flask(__name__)
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
#app.route('/foo', methods=['GET','POST','OPTIONS'])
#crossdomain(origin="*")
def foo():
return request.json['inputVar']
if __name__ == '__main__':
app.run()
Can you please give some some indication of why that is?

You can get the results with a simple:
#app.route('your route', methods=['GET'])
def yourMethod(params):
response = flask.jsonify({'some': 'data'})
response.headers.add('Access-Control-Allow-Origin', '*')
return response

Well, I faced the same issue. For new users who may land at this page.
Just follow their official documentation.
Install flask-cors
pip install -U flask-cors
then after app initialization, initialize flask-cors with default arguments:
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
#app.route("/")
def helloWorld():
return "Hello, cross-origin-world!"

It worked like a champ, after bit modification to your code
# initialization
app = Flask(__name__)
app.config['SECRET_KEY'] = 'the quick brown fox jumps over the lazy dog'
app.config['CORS_HEADERS'] = 'Content-Type'
cors = CORS(app, resources={r"/foo": {"origins": "http://localhost:port"}})
#app.route('/foo', methods=['POST'])
#cross_origin(origin='localhost',headers=['Content- Type','Authorization'])
def foo():
return request.json['inputVar']
if __name__ == '__main__':
app.run()
I replaced * by localhost. Since as I read in many blogs and posts, you should allow access for specific domain

Might as well make this an answer. I had the same issue today and it was more of a non-issue than expected. After adding the CORS functionality, you must restart your Flask server (ctrl + c -> python manage.py runserver, or whichever method you use)) in order for the change to take effect, even if the code is correct. Otherwise the CORS will not work in the active instance.
Here's how it looks like for me and it works (Python 3.6.1, Flask 0.12):
factory.py:
from flask import Flask
from flask_cors import CORS # This is the magic
def create_app(register_stuffs=True):
"""Configure the app and views"""
app = Flask(__name__)
CORS(app) # This makes the CORS feature cover all routes in the app
if register_stuffs:
register_views(app)
return app
def register_views(app):
"""Setup the base routes for various features."""
from backend.apps.api.views import ApiView
ApiView.register(app, route_base="/api/v1.0/")
views.py:
from flask import jsonify
from flask_classy import FlaskView, route
class ApiView(FlaskView):
#route("/", methods=["GET"])
def index(self):
return "API v1.0"
#route("/stuff", methods=["GET", "POST"])
def news(self):
return jsonify({
"stuff": "Here be stuff"
})
In my React app console.log:
Sending request:
GET /stuff
With parameters:
null
bundle.js:17316 Received data from Api:
{"stuff": "Here be stuff"}

I might be a late on this question but below steps fixed the issue
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app)

Note that setting the Access-Control-Allow-Origin header in the Flask response object is fine in many cases (such as this one), but it has no effect when serving static assets (in a production setup, at least). That's because static assets are served directly by the front-facing web server (usually Nginx or Apache). So, in that case, you have to set the response header at the web server level, not in Flask.
For more details, see this article that I wrote a while back, explaining how to set the headers (in my case, I was trying to do cross-domain serving of Font Awesome assets).
Also, as #Satu said, you may need to allow access only for a specific domain, in the case of JS AJAX requests. For requesting static assets (like font files), I think the rules are less strict, and allowing access for any domain is more accepted.

Note: The placement of cross_origin should be right and dependencies are installed.
On the client side, ensure to specify kind of data server is consuming. For example application/json or text/html
For me the code written below did magic
from flask import Flask,request,jsonify
from flask_cors import CORS,cross_origin
app=Flask(__name__)
CORS(app, support_credentials=True)
#app.route('/api/test', methods=['POST', 'GET','OPTIONS'])
#cross_origin(supports_credentials=True)
def index():
if(request.method=='POST'):
some_json=request.get_json()
return jsonify({"key":some_json})
else:
return jsonify({"GET":"GET"})
if __name__=="__main__":
app.run(host='0.0.0.0', port=5000)

I used decorator given by Armin Ronacher with little modifications (due to different headers that are requested by the client).And that worked for me. (where I use angular as the requester requesting application/json type).
The code is slightly modified at below places,
from flask import jsonify
#app.route('/my_service', methods=['POST', 'GET','OPTIONS'])
#crossdomain(origin='*',headers=['access-control-allow-origin','Content-Type'])
def my_service():
return jsonify(foo='cross domain ftw')
jsonify will send a application/json type, else it will be text/html.
headers are added as the client in my case request for those headers
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Access-Control-Allow-Origin':'*'
})
};
return this.http.post<any>(url, item,httpOptions)

I think the problem is with preflighted requests.
It seems there's no effective way to disable the automatic answer to OPTIONS request if you're using #route #put #patch #delete decorators.
my workaround is the following snippet at the start of the api (before any decorated function)
def option_todo(id):
return '', 204
app.add_url_rule('/', view_func=option_todo, provide_automatic_options=False, methods=['OPTIONS'])
app.add_url_rule(r'/<path:path>', view_func=option_todo, provide_automatic_options=False, methods=['OPTIONS'])
#app.after_request
def after_request(response):
response.headers['Access-Control-Allow-Methods']='*'
response.headers['Access-Control-Allow-Origin']='*'
response.headers['Vary']='Origin'
return response

This is a pretty old and well-covered question already, but figured I'd contribute what I think is the simplest solution of the lot:
#app.after_request
def after_request(response: Response) -> Response:
response.access_control_allow_origin = "*"
return response

I encountered this issue today, and none of the answers worked for me.
I set the cross_origin() decorator as follows:
#app.route('/', methods = ['POST'])
#cross_origin()
def index():
Then I did:
Open the Flask Python file in the IDE.
Right mouse-click on the file.
Click: Run Python File in Terminal
The problem for me was running the Flask Python file with CTRL+ALT+N. The "Run Code" button in VSCode, I shouldn't have ran the Flask server that way. Because of that I assume CORS didn't load properly.
Also, my print()s didn't always appear, because of that so it was also hard to debug stuff. This happened because by running the app via CTRL+ALT+N, VSCode focusses on the OUTPUT window instead of the TERMINAL window.
Also, print()s that did appear in the OUTPUT window, don't support emojis like the TERMINAL window does. So my app crashed for the longest time until I figured it all out.
Stupid mistake on my part though, should've known better. Hope this helps others!

My issue was a preflight one, but I had to add to app.py
...
#app.after_request
def after_request(response: Response) -> Response:
response.access_control_allow_credentials = True
return response

My fix was
#app.after_request
def handle_options(response):
response.headers["Access-Control-Allow-Origin"] = "*"
response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS"
response.headers["Access-Control-Allow-Headers"] = "Content-Type, X-Requested-With"
return response

I struggled a lot with something similar. Try the following:
Use some sort of browser plugin which can display the HTML headers.
Enter the URL to your service, and view the returned header values.
Make sure Access-Control-Allow-Origin is set to one and only one domain, which should be the request origin. Do not set Access-Control-Allow-Origin to *.
If this doesn't help, take a look at this article. It's on PHP, but it describes exactly which headers must be set to which values for CORS to work.
CORS That Works In IE, Firefox, Chrome And Safari

Related

No 'Access-Control-Allow-Origin' header is present on the requested resource. when running a Python script using Javascript

I am new to AJAX and Flask and I am trying to make a Chrome extension that runs a Python script from Javascript. The script moves the mouse at a certain coordinate and clicks there.
This is the Javascript code:
function click_coord() {
$.ajax({
url: "http://127.0.0.1:5000/click_coord/",
type: "POST",
success: function(resp){
console.log(resp);
}
});
}
This is the Python code:
from flask import Flask, jsonify
from flask_cors import CORS, cross_origin
from pynput.mouse import Button, Controller
app = Flask(__name__)
cors = CORS(app)
app.config['CORS_HEADERS'] = 'Content-Type'
#app.route('/click_coord/', methods=['POST'])
def click_coord():
move_mouse()
a = 15
b = 17
return jsonify(a+b)
def move_mouse():
mouse = Controller()
mouse.position = (201, 549)
mouse.press(Button.left)
mouse.release(Button.left)
if __name__ == "__main__":
app.run(debug=True)
The error I get is: No 'Access-Control-Allow-Origin' header is present on the requested resource. I only get this error if I call the function "move_mouse". If I don't, the code runs properly.
I saw in another post that a person had a problem because they didn't add the correct permissions but i added: "permissions": ["tabs", "http://localhost/*"] to the Json manifest
Try adding a resource to your CORS(app, resources={r"": {"origins": ""}})

How to respond to a GET request in tornado?

Just started learning HTTP, trying to make a simple client-to-server request to work in tornado. Here is my javascript function trigged by a button click:
function funcOnClick(){
$.ajax({
url: "http://localhost:8889/madTest",
type: "GET",
success: function(result){alert('success')},
error: function(error){console.log(error)}
})
}
And here is my server:
import tornado.ioloop
import tornado.web
import json
class MainHandler(tornado.web.RequestHandler):
def get(self):
print('got the GET request')
self.write('abc')
def make_app():
return tornado.web.Application([
(r"/madTest", MainHandler),
])
if __name__ == "__main__":
app = make_app()
app.listen(8889)
print('server started, listening to 8889 ...')
tornado.ioloop.IOLoop.current().start()
On clicking the button, I see "got the GET request" printed, so the server must have gotten the request. However, I got this error on console:
Any suggestions? Thanks!
The error message occurs when your JS or HTML page is served from a different domain and you're trying to make an AJAX request to a different domain. This is called CORS. For security reasons, web browsers restrict cross-domain AJAX requests unless allowed by the server.
To be able to make cross origin AJAX requests, you'll need to set a header called Access-Control-Allow-Origin in your handler's response.
You can do this in the prepare method of your handler:
class MainHandler(...):
def prepare(self):
self.set_header('Access-Control-Allow-Origin', '*')
# the wildcard - '*' - allows CORS from any domain
# you should probably change it to your frontend
# domain name if you wan to restrict CORS to a single domain.
# see Mozilla docs for more info

dojo/request PUT method dosn't work

I have a web app using Python Django and Dojo framework.
I wanna send a PUT request from Dojo (using dojo/request) to server Django but when server receives a request, the data within are empty and validate Invalid.
BUT when I change method from PUT to POST, it's work correctly.
Here is my code:
_save: function(data){
var idForm = "editForm" + this.id;
var value = dijit.byId(idForm).get('value');
console.log(value);
request.put("/api/guestbook/"+this.bookName+"/greeting/"+this.id+"/", {
data: {
book_name: this.bookName,
message: value.message
},
headers: { "X-CSRFToken": _cookie('csrftoken') }
}).then(lang.hitch(this, function(text){
}));
},
And in Django:
def put(self, request, *args, **kwargs):
form = self.get_form(self.form_class)
logging.warning(form)
logging.warning(request.PUT)
if form.is_valid():
logging.warning("This form is VALID")
else:
logging.warning("This form is INVALID!!!")
Anyone can help me?
Thanks for help!
I found the way to receive PUT method below:
def put(self, request, *args, **kwargs):
request.PUT = QueryDict(request.body)
form = self.form_class(request.PUT)
if form.is_valid():
logging.warning("This form is VALID")
else:
logging.warning("This form is INVALID")
This is ok :)
Thanks all!
I'm guessing from your X-CSRFToken header that you are doing cross domain requests, i.e. CORS.
If you look in your browser's console, you'll probably see an OPTIONS request being sent to the server. This is called a "preflight request", and your server needs to respond with CORS headers telling the browser that it's okay to make the cross domain PUT request.
In your case, you want the server to respond with headers similar to:
Access-Control-Allow-Origin: http://your-site-hostname-and-port
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-CSRFToken
Simple POST requests do not need the preflight OPTIONS request, that's probably why it works. A pretty good tutorial on html5rocks here.

POST json data to Bottle

I am a newbie to Bottle and sort of to Python as well and I am trying create an app whenever I click a button, an AJAX is fired and POST a json to server and store it using SQLite.
However, at current stage, I am trying to figure out how do I successfully received the data in the server.
On the client side,
I have the following send_data function written in JavaScript.
function send_data(feedback) {
$.ajax({
url: "/feedback",
type: "POST",
data: JSON.stringify(feedback),
contentType: "application/json",
success: function() {
alert("Feedback successfully stored in the server!");
},
error: function() {
alert("Feedback failed to store back in the server!");
},
}
The passed in parameter feedback looks something like {"id1": 1, "id2": 2}.
On the server side, I have a feedback.py file and the code is
from bottle import request, route, run
#route('/feedback', method='POST')
def feedback():
comments = request.json
print comments
run(host='localhost', port=8080)
Right now, I just want to check if I have received the data successful. But everytime, when I click that botton, I receive the following error
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/feedback. This can be fixed by moving the resource to the same domain or enabling CORS.
OPTIONS http://localhost:8080/feedback [HTTP/1.0 405 Method Not Allowed 2ms]
I am not sure if it's because I am not using the element <form>. That botton is technically just an image. Every time I click that image, send_data() function is fired.
Anyone can help? I really appreciate it. Thank you!
Cross Origins Requests are restricted as a security measure by the browser. It is possible to overcome that by setting an Access-Control-Allow-Origin header. You can can use bottle-cors or create a decorator like the following on your server code (Python/bottle):
def enable_cors(fn):
def _enable_cors(*args, **kwargs):
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, OPTIONS'
response.headers['Access-Control-Allow-Headers'] = 'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token'
if request.method != 'OPTIONS':
# actual request; reply with the actual response
return fn(*args, **kwargs)
return _enable_cors
and then with your example:
from bottle import request, route, run
#enable_cors
#route('/feedback', method='POST')
def feedback():
comments = request.json
print comments
run(host='localhost', port=8080)
Note that it's best to allow specific origins instead of using *.
You can read more about Cross-Origin Resource Sharing (CORS) here
You can make this work by disabling the Cross-origin restrictions.
On safari, open the Develop panel, and check disable cross-origin restrictions, or use a browser like Firefox.

webapp2 and the Access-Control-Allow-Origin

I'm using webapp2 in a google app engine app. Basically I have built a REST API and I am trying to connect to it from a javascript ajax client. The problem I am facing is in how to correctly implement the Access-Control-Allow-Origin header thing. I have a solution that works but looks pretty clunky to me. Can anyone suggest a better way?
Here is my current solution:
in my main routing file i have:
webapp2.Route(r'/<v>/logins/simple',
handler=controllers.login_c.LoginController,
name='simple_login', handler_method='simple_login',
methods=['GET', 'POST', 'OPTIONS']),
and then in the controller:
class LoginController(webapp2.RequestHandler):
def simple_login(self, v):
self.response.headers.add_header('Access-Control-Allow-Origin', '*')
self.response.headers.add_header('Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept')
self.response.headers.add_header('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE')
self.response.headers.add_header('Content-Type', 'application/json')
if not self.request.__str__().startswith("OPTIONS"):
...more code
But this solution means i have to duplicate the headers thing in each controller. Can't I have something to catch all the OPTIONS requests?
Was going over this today, and the OP's question:
Can't I have something to catch all the OPTIONS requests?
...is one that I had, too. I created a wrapper class that my restful endpoint classes could inherit from, and it includes a default OPTIONS handler. This can also be done in the dispatch method as well, as demonstrated in this SO post.
main.py
import webapp2
from controllers import widgets_controller
APP = webapp2.WSGIApplication([
('/rest/widgets/all', widget_controller.All),
('/rest/widgets/create', widget_controller.Create),
], debug=True)
widgets_controller.py
class Create(rest.RestHandler):
def post(self):
# We use this for any POST, PUT, and DELETE, where necessary.
self.decorateHeaders();
# Handle the rest of the request here...
rest_controller.py
class RestHandler(webapp2.RequestHandler):
def decorateHeaders(self):
"""Decorates headers for the current request."""
self.response.headers.add_header('Access-Control-Allow-Origin', '*')
self.response.headers.add_header('Access-Control-Allow-Headers', 'Authorization')
self.response.headers.add_header('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE')
def options(self):
"""Default OPTIONS handler for the entire app."""
self.decorateHeaders()
Why route all to a single method: simple_login. Why not use a def options(self) in your handler?
I use something like:
class RPCHandler(webapp.RequestHandler):
def options(self):
self.response.headers['Access-Control-Allow-Origin'] = '*'
self.response.headers['Access-Control-Allow-Headers'] = '*'
self.response.headers['Access-Control-Allow-Methods'] = 'POST, OPTIONS'
def post(self):
self.response.headers['Access-Control-Allow-Origin'] = '*'
self.response.headers['Access-Control-Allow-Headers'] = '*'
self.response.headers['Access-Control-Allow-Methods'] = 'POST, OPTIONS'
.... more code to handle the rpc ....
def main():
app = webapp.WSGIApplication([
('/', MainPage),
('/rpchr', RPCHandler),
], debug=True)
util.run_wsgi_app(app)
if __name__ == '__main__':
main()
Example taken from some old webapp Python 2.5 application for handling json requests. But it is working fine for a couple of years now.
from app.yaml:
- url: /rpchr
script: main.py
secure: always
- url: /
script: main.py
secure: always
login: admin
But now we have cloud endpoints.

Categories