Enable CORS in a Backbone client with a Flask server - backbone.js

I want to do cross domain requests between my backbone app at 127.0.0.1 and and my Flask server at 127.0.0.1:5000. Before I switched to a Backbone I had an Ember.js app and I had the same problem. But I got it working by adding this in my Flask app:
#app.after_request
def after_request(data):
response = make_response(data)
response.headers['Content-Type'] = 'application/json'
response.headers['Access-Control-Allow-Origin'] = 'http://localhost'
return response
and configure the Ember RESTAdapter this way:
adapter: DS.RESTAdapter.create({
url : 'http://127.0.0.1:5000',
// In order to allow cross domain requests
ajax: function(url, type, hash) {
jQuery.ajax(url)
}
})
});
But this does not work with my Backbone application.
XMLHttpRequest cannot load http://127.0.0.1:5000/files.
Request header field Content-Type is not allowed by Access-Control-Allow-Headers.
I guess I've to change some settings on the client side. But I don't know what.
What do I've to do so that I am able to to do cross domain requests?

Here is what worked for me.
http://flask-cors.readthedocs.org/en/latest/
$ pip install -U flask-cors
from flask import Flask
from flask.ext.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!"

I got it working by adding
response.headers['Access-Control-Allow-Headers'] = "Origin, X-Requested-With,Content-Type, Accept" to the after_request() method.

For development you can:
Use Chrome extension - https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi
Start chrome in unsecured mode - https://stackoverflow.com/a/3177718/1104483
Or just set Access-Control-Allow-Origin to *

Related

Why React can't reach Flask endpoints in production?

I've got a React app with Flask on the backend in production and I found out
that none of my endpoints are reached from React.
I'm aware that when using client-side routing developer needs to use a catch-all function
similar to the below:
#app.errorhandler(404)
def error_handler(e):
return render_template('index.html')
I'm using Flask-CORS to handle cross origin requests:
within config.py:
class ProductionConfig:
CORS_HEADERS = 'Content-Type'
...
...
my blueprint:
CORS(auth_blueprint, resources={r'/*': {"origins": "https://example.com", "allow_headers": "*", "expose_headers": "*"}})
#auth_blueprint.route('/auth/login', methods=['POST'])
#cross_origin()
def login():
...
...
on the frondend I'm defining headers like this:
const headers = { "Access-Control-Allow-Origin": "*" };
const url = "https://example.com:5000/auth/login";
axios.post(url, data, headers).then(resp => { ... })
And I'm not getting any errors whatsoever. Server's logs are clean and the console only shows Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://example.com:5000/auth/login. (Reason: CORS request did not succeed).
"Reason: CORS request did not succeed" means that the server didn't return anything.
The app renders fine however React (axios) can't reach my endpoints. Are there any gotchas I'm not aware of ? When request is sent I'm not even getting a status code in the network tab.
Thank you.
Screenshot of the network tab:
You need to change the connection protocol to http.

https associated to an insecure XMLHttpRequest endpoint

My website is hosted on a cloud run app : https://ap4-xxxxxxxx.a.run.app/.
This website is calling an API which is hosted here https://ap4-xxxxxxxx.a.run.app/api/undefined. But this request is blocked in my browser .
Error message :
Mixed Content: The page at 'https://ap4-xxxxxxxx.a.run.app/' was
loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint
'http://ap4-xxxxxxxx.a.run.app/api/undefined/'. This request has been
blocked; the content must be served over HTTPS.
The API https://ap4-xxxxxxxx.a.run.app/api/undefined is working perfectly on my browser or with postman. And the code requesting it explicitly mentionned https :
const request = https://ap4-xxxxxxxx.a.run.app/api/${variable};
axios.get(request)
.then(result => {
const PlaceList = result.data.map(
station => {
const isFavorite = PlaceId.includes(Place.number);
return { ...Place, isFavorite: isFavorite }
}
);
this.setState({
PlaceList: PlaceList,
isLoading: false
})
updateFavPlaceList(PlaceList);
})
I don't understand what's wrong here. Is my app making an http call instead of https ? I read here (Page loaded over HTTPS but requested an insecure XMLHttpRequest endpoint) that, some https are self signed. Is it the case of cloud run?
I've tried Cors, but it did not help.
Any observation or suggestion would be very much appreciated.
It seems you are indeed somewhere making an HTTP:// request in your frontend or make sure your app doesn't issue redirects to http://.
.app domains are in hardcoded HSTS list of your browser. If you type any .app domain, it will be requested as https:// .There's no way to access a .app domain over http:// in a modern browser, even with XHR.
So here is a quick fix. I forced my backend (flask) to generate https url.
Using the answer from here : Flask url_for generating http URL instead of https
class ReverseProxied(object):
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
scheme = environ.get('HTTP_X_FORWARDED_PROTO')
environ['wsgi.url_scheme'] = 'https'
app = Flask(__name__)
app.wsgi_app = ReverseProxied(app.wsgi_app)
There might be a better way (maybe forcing the frontend to request https), so feel free to comment on this.

Flask API deployed with Heroku 'CORS blocked' error

I'm having issues on my application that has been deployed to Heroku. When I was developing it on localhost, I didn't get this error, but once I deployed it, it spontaneously throws this error:
Access to fetch at
'https://frontend.herokuapp.com' from origin
'https://backend.herokuapp.com' has been blocked
by CORS policy: No 'Access-Control-Allow-Origin' header is present
on the requested resource. If an opaque response serves your needs,
set the request's mode to 'no-cors' to fetch the resource with CORS
disabled.
Simplified version of my Flask server:
from flask import Flask, request, make_response, jsonify, url_for,
redirect, render_template
from flask_cors import CORS, cross_origin
import flask
import json
app = Flask(__name__)
CORS(app)
#app.route('/api/action', methods=['GET', 'POST'])
#cross_origin()
def prescription(response={}):
# POST request
if request.method == 'POST':
print('score POST request')
response = request.get_json()
data = json.loads(response.get('data'))
rating = a_super_cool_feature
return jsonify(rating), 200
# GET request
else:
print('GET request')
return getScore(response)
#app.route('/api/score', methods=['GET', 'POST'])
#cross_origin()
def scoreHandler(response={}):
# POST request
if request.method == 'POST':
print('Incoming..')
response = request.get_json()
parseResponse(response)
return str(getScore(response)), 200
# GET request
else:
return getScore(response)
#app.route('/test')
def test_page():
# look inside `templates` and serve `index.html`
return render_template('index.html')
if __name__ == "__main__":
app.debug=True
app.run()
My front-end is a React application. These two servers run on separate Heroku servers and I'm using the free version so I only get one dyno at a time (in case this could cause this error).
The interesting thing is this:
About half the time, when these POST requests are called on the deployed Heroku app, the error is thrown. Otherwise, it works no problem. Any ideas on fixing this?
You could use this snippet to enable cors app wide.
from flask import Flask
from flask_cors import CORS
app = Flask(__name__) CORS(app)
Okay now I actually fixed it. I bought the "Hobby" dyno type in Heroku and I never get the error now. I think it just has to do with the other server not being up and running when I make the request because I can only have one dyno running at a time with the free version. Thus it somehow timed out and gives that error.
With the Hobby dyno type my backend is always running so when I make a request it no longer times out and gives that error.
Really weird psuedo fix. Basically it was giving me this error about 40% of the time I made the POST request to the Flask backend, then I added
app.config['CORS_HEADERS'] = 'Content-Type'
Under the:
app = Flask(__name__)
CORS(app)
And this did not fix the issue completely. However; now this error is only thrown about 5% of the time when requests are made to the back-end. See other answer for actual fix.

React app using API with another origin (CORS)

I have a react app, which uses a java ee backend rest server, running on another domain. I have enabled CORS:
Access-Control-Allow-Origin : http://localhost:3000
Access-Control-Allow-Headers : origin, content-type, accept, authorization
Access-Control-Allow-Credentials : true
Access-Control-Allow-Methods : GET, POST, PUT, DELETE, OPTIONS, HEAD
Access-Control-Max-Age : 1209600
I am using react with fetch like this:
export function get(path, headers) {
return fetch(apiUrl + path, {
"metod" : "GET",
"headers" : headers,
"credentials" : "include"
})
}
My react app is running on http://localhost:3000.
When I am logging in, the server returns the Set-Cookie, but the cookie is not included in any further request to the server, unless I try to log in again. Then it is included for that specific login request.
Any suggestions?
I just want to share how I make my local development painless by this post if you are using create-react-app by just adding your main API url proxy to your package.js for example "proxy": "http://localhost:8080/API"
No need to setup CORS on your backend.
Install this.
https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi?hl=es
Once installed, click on his BrowserIcon and toggle on. It is all. You will not receive more error.
EDIT. Solution for Production
If you want config it from your server (or simply not adding a browser extension, try this:)
If you are using node.js do the following: node.js server file: response.writeHead(200, { 'Content-Type': contentType, 'Access-Control-Allow-Origin': '*' })
fetch('http://ajax.googleapis.com/ajax/services/feed/load?v=‌​1.0&num=8&q=http://r‌​ss.cnn.com/rss/editi‌​on_entertainment.rss‌​?output=rss', { method: 'get', mode: 'no-cors', }).then(() => { console.log('Works!'); });
Other solution:If you are using PHP too you can add: <?php header('Access-Control-Allow-Origin: *'); ?> into your PHP File. As I see, it is not the case, so... In your server (eg: Apache) add this directive: Header set Access-Control-Allow-Origin * in Settings (as the first option).
So, I solved the problem by using another stackoverflow thread and robertklep's comment. As stated here: "When working on localhost, the cookie domain must be omitted entirely.". I implemented robertkleps idea, but did not set the domain. It resulted in a Set-Cookie like this: Set-Cookie:kek=7fukucsuji1n1ddcntc0ri4vi; Version=1; Path=/; Max-Age=100000. This works fine.
To add more on existing answers.
With react you can use "proxy" in your package.json to avoid CORS.
Basically if you need to reach localhost:8100 (your java backend) and your react app run on localhost:3000
You can set:
In your package.json
"proxy": "http://localhost:8100"
And then when you want to make a get to /hello which would be an endpoint of your java API you can do:
import axios from 'axios';
axios.get('/hello')
.then(resp => {
console.log(resp.data);
});
And it will be redirected to http://localhost:3000/hello so you will avoid CORS.

Call Django API running on a server from Angular running locally

I am learning with Django and Angular.
I have setup a Django API back-end on on http://serverip:8666/athletics/
I have created a small Angular application that I am running from my local machine.
The following code in my Angular app:
$scope.list_athletes = function(){
console.log('hey');
$http
.get('http://serverip:8666/athletics/')
.success(function (result) {
console.log('success');
})
}
generates the error:
XMLHttpRequest cannot load http://serverip:8666/athletics/. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://127.0.0.1:65356' is therefore not allowed
access.
What causes this error? How can I resolve it so that I can access the Django API from my local Angular app?
The problem you're having is related to not having CORS enabled.
As a security policy, JavaScript can't make requests across domains while running in your browser. This is meant to prevent untrusted code from executing without the user's knowledge. The workaround is to enable CORS by white listing domains.
You need to set the Access-Control-Allow-Origin response header in your responses like so:
def my_view(request):
data = json.dumps({'foo':'bar'})
response = HttpResponse(data)
response['Access-Control-Allow-Origin'] = 'http://127.0.0.1:65356'
return response
This will enable CORS for your angular app. You can even add django-cors-headers to your project to have this functionality implemented for you. This can be added to any Django response object, such as django.http.repsonse.HttpResponse. Because you appear to be using a DRF Response object, you may need to use something like
return Response(serializer.data, headers={'Access-Control-Allow-Origin': 'http://127.0.0.1:65356'})
to set your response headers.
You should also check out this site for more information on how to enable CORS in your webapp.
Have you done the settings part in settings.py
INSTALLED_APPS = (
'corsheaders',
)
MIDDLEWARE_CLASSES = (
'corsheaders.middleware.CorsMiddleware',
)
CORS_ORIGIN_WHITELIST = (
'http://127.0.0.1:65356'
)
And also include CORS_ALLOW_CREDENTIALS, CORS_ALLOW_HEADERS settings

Resources