Cross Domain with CherryPy - cross-domain

I have a JBOSS server running on port :8080 and a CherryPY server running on :8099
If I attempt to do the following
var insertObj = {
poi_id : "12345",
obv_id : ""
};
var url = "http://10.XX.X.XXXX:8099/output";
$.ajax({
type : "GET",
url : url,
data : JSON.stringify(insertObj),
contentType : "application/json",
dataType : "json",
success : function(response) {
alert(response);
}
});
EDIT 1:
This is how I've set up my cherryPy server
class TestServer(object):
#cherrypy.expose
def index(self):
return "Hello World!"
#cherrypy.expose
#cherrypy.tools.json_out()
#cherrypy.tools.json_in()
def test(self):
print 'set up the response headers'
cherrypy.response.headers["Access-Control-Allow-Origin"] = "http://localhost"
cherrypy.response.headers["Allow"] = "POST, GET"
input_json = cherrypy.request.json
print input_json
def CORS():
cherrypy.response.headers["Access-Control-Allow-Origin"] = "*" # mean: CORS to all; insert spec. origin to allow spec access
# ... insert further resp headers if needed
if __name__ == '__main__':
cherrypy.tools.CORS = cherrypy.Tool('before_handler', CORS)
port = int(os.environ.get('PORT', 8099))
cherrypy.config.update({'server.socket_host': '10.XX.X.XXX',
'server.socket_port': port,
'tools.CORS.on': True,
})
cherrypy.quickstart(TestServer())
However, I still get the same issue in Chrome/Firefox/IE
XMLHttpRequest cannot load http://10.XX.X.XXX:8099/test. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://10.XX.X.XXX:8080' is therefore not allowed access.

Related

Python passing arguments to function Flask

I am writing a Flask application script and have encountered a function that accepts arguments and functions outside of the flask app in a standalone script but will not accept the the 'TFEVT_node_id'argument I pass to it inside of the Flask app. Here is the Flask code:
#################################################
# Flask Setup
#################################################
#app = Flask(__name__, static_url_path='')
app = Flask(__name__)
CORS(app)
#################################################
#global variables
TFEVT_node_id = ''
token = ''
#################################################
# CityIQ API calls
#################################################
def get_token():
print("Get Token")
url = 'https://auth.aa.cityiq.io/oauth/token'
querystring = {"grant_type":"client_credentials"}
response = requests.get(url, auth=HTTPBasicAuth(client,secret), params=querystring).json()
token = response['access_token']
print("Token Received")
return token
#given a specific subasset this function returns the CityIQ traffic events for a given period of time in minutes
def get_traffic(TFEVT_node_id, lookback_minutes):
url_string = '/events'
url = "https://sandiego.cityiq.io/api/v2/event/assets/"+TFEVT_node_id+url_string
ts = datetime.datetime.now().timestamp()
CityIQ_Current_TS = int(ts*1000)
CityIQ_TS_Calc_TS = datetime.datetime.now() - timedelta(minutes=lookback_minutes)
CityIQ_Starttime_TS = int((ts-(lookback_minutes*60))*1000)
querystring = {"eventType":"TFEVT","startTime":CityIQ_Starttime_TS,"endTime":CityIQ_Current_TS,"pageSize":"100"}
payload = ""
headers = {
'Authorization': "Bearer {}".format(token),
'Predix-Zone-Id': "SD-IE-TRAFFIC",
'cache-control': "no-cache",
}
response = requests.request("GET", url, headers=headers, params=querystring).json()
return(response)
#give it an CityIQ node ID and it will return the asset TFEVT child .
def get_asset_TFEVT(node_id):
url = "https://sandiego.cityiq.io/api/v2/metadata/assets/"+node_id+"/subAssets"
payload = ""
headers = {
'Authorization': "Bearer {}".format(token),
'Predix-Zone-Id': "SD-IE-ENVIRONMENTAL",
'cache-control': "no-cache",
}
response = requests.request("GET", url, data=payload, headers=headers).json()
for i in response['assets']:
if any('TFEVT' in i for i in [i][0]['eventTypes']):
global TFEVT_node_id
TFEVT_node_id = ([i][0]['assetUid'])
return(TFEVT_node_id)
#test def that should be removed in production
def test(TFEVT_node_id, lookback_minutes):
found_cars = get_traffic(TFEVT_node_id, lookback_minutes)
print(found_cars)
return(found_cars)
#################################################
# Flask Routes
#################################################
#app.route('/')
def hello_world():
global token
token = get_token()
return 'documentation comming soon!'
#app.route('/test/<string:node_id>')
def go(node_id):
global token
token = get_token()
global TFEVT_node_id
TFEVT_node_id = get_asset_TFEVT(node_id)
cars_list = []
lookback_minutes = 15
env_output = {}
ccars = test(TFEVT_node_id, lookback_minutes)
cars_list.append(ccars)
env_output.update({'Cars' : cars_list})
if __name__ == '__main__':
app.run()
Again, I am getting the desired result when these functions are run outside of a Flask app. Inside of the Flask app (running the code above) returns a TypeError: The view function did not return a valid response. I have traced that back to the 404 response in the gettraffic function where the lookback minutes variable is getting through but the TFEVT_node_id isn't.
I am new to Python.
Your go() function does not have a return. A response is expected. See: About responses.

Why aren't my AJAX requests going through?

This is my github repository for this live demo I have going on at the moment.
//index.js is where the POST request is being sent from
class Index extends React.Component {
state = {
loading: false,
};
handleClickLoading = () => {
this.setState(state => ({
loading: true,
}));
var jqXHR = $.ajax({
type: "POST",
url: "http://localhost:5000/login",
async: true,
data: { mydata: [Cookies.get('links'), Cookies.get('numSentences')] },
success: function(){
const data = JSON.parse(jqXHR.responseText);
console.log(data);
}
});
Cookies.set('final', jqXHR.responseText);
console.log(jqXHR.responseText)
};
render() {
const {loading} = this.state;
return (
<div>
<AppBar/>
<Block/>
<Card>
<CardActions>
<Button size="large"
fullWidth={true}
onClick={this.handleClickLoading}>Submit</Button>
</CardActions>
</Card>
<Fade
in={loading}
unmountOnExit
>
<BottomBar/>
</Fade>
</div>
)
}
}
export default Index;
and its trying to get data ran through python scripts through a Flask server:
...
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, list):
headers = ', '.join(x.upper() for x in headers)
if not isinstance(origin, list):
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("/")
def home():
return "hi"
#app.route("/index")
#app.route('/login', methods=['GET', 'POST', 'OPTIONS'])
#crossdomain(origin='*')
def login():
message = None
if request.method == 'POST':
datafromjs = request.form['mydata']
result = "test"
resp = make_response('{"response": '+result+'}')
resp.headers['Content-Type'] = "application/json"
resp.headers.add('Access-Control-Allow-Origin', '*')
resp.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
resp.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS')
return resp
return render_template('login.html', message='')
if __name__ == "__main__":
app.run(debug = True)
And this is the console output onClick from the browser:
and Flask:
The javascript is trying to fetch the output of a few python functions given a few parameters.
I'm just at an impasse here and it's the last cog in my project. I have no prior experience with this kind of stuff but any help is appreciated!
I believe this is a CORS issue, like JJ Hakala points out. Even if you are going to the same domain (localhost) but on a different port (8080 -> 5000) then you need an authorisation header to be present (server side).
If you can ensure that the header access-control-allow-origin:* is present (a wildcard domain approach) in server responses, then you should have no more ajax issues.
https://en.wikipedia.org/wiki/Cross-origin_resource_sharing

Flask's test_client() is not passing custom HTTP Headers to the Flask app

I have something like this in my test script:
def setUp(self):
app = create_app()
self.app = app.test_client()
def test_001(self):
with self.app as app:
headers = { 'API-KEY': 'myKey' }
app.get('/endpoint1', follow_redirects=True,headers=headers)
Reading through the print statements from my application, I can see that my application endpoint is called, and things look normal except for the header missing from the request.
In my API, I have this print statement:
log("Headers: " + str(request.headers))
This output the following messages in the console:
Headers: User-Agent: werkzeug/0.14.1
Host: localhost
Content-Length: 0
So apparently, the client does send some headers, but not the custom one I added.
Does anyone see what I'm doing wrong, that causes the headers either not to be sent in the first place, or them not being accessible to the server?
def setUp(self):
self.app = create_app()
self.app.config['TESTING'] = True
self.app_context = self.app.app_context()
self.app_context.push()
self.client = self.app.test_client()
def test_001(self):
headers = { 'API-KEY': 'myKey' }
response = self.client.get('/endpoint1', follow_redirects=True, headers=headers)
For anyone still struggling:
using follow_redirects=True somehow looses the headers on redirect.
Simple workaround is to do the redirect yourself:
headers = { 'KEY': '123' }
code = 301
url = '/v1/endpoint'
while code == 301:
response = client.get(url, headers=headers)
code = response._status_code
if code == 301: #'Location' is only in header if 301
url = response.headers['Location']

Postman able to use GET request properly but my program cannot

I have a GET and PUT request built below:
from flask import Flask
from flask_restful import Api, Resource, reqparse
app = Flask(__name__)
api = Api(app)
userStorage =[
{
"id": "1234",
"currentBot": "BestBot"
}
]
class User(Resource):
def get(self, id):
for user in userStorage:
if(id == user["id"]):
return user, 200
return "User not found", 404
def put(self, id):
parser = reqparse.RequestParser()
parser.add_argument("currentBot")
args = parser.parse_args()
for user in userStorage:
if(id == user["id"]):
user["currentBot"] = args["currentBot"]
return user, 200
user = {
"id": id,
"currentBot": args["currentBot"]
}
userStorage.append(user)
return user, 201
def delete(self, id):
global userStorage
userStorage = [user for user in userStorage if user["id"] != id]
return "{} is deleted.".format(id), 200
api.add_resource(User, "/user/<string:id>")
app.run(debug = True, port = 4000)
Postman can properly get a response 200 when I do a simple get request but when I try to do a request through my own program it returns a 404
import requests
payload2Storage = {
"currentBot": "BestBot"
}
headers = {"Content-Type": "application/json"}
params = {
"id": "1234"
}
#response = requests.request("PUT", "http://127.0.0.1:4000/user/", data=payload2Storage, params=params, headers=headers)
response2 = requests.request("GET", "http://127.0.0.1:4000/user/", params=params, headers=headers)
Is there something wrong with my request to get the info from userStorage?
In the client code, changing from 127.0.0.1 to localhost worked for me. Try this:
response2 = requests.request("GET", "http://localhost:4000/user/", params=params, headers=headers)
OR in the server code, bind the server to 127.0.0.1 explicitly via host argument like this:
app.run(debug = True, port = 4000, host='127.0.0.1')
Other error in the code is user["id"] returns a str while id is a int, change the code as below:
def get(self, id):
for user in userStorage:
if(id == int(user["id"])):
return user, 200
return "User not found", 404

Origin http://localhost:8000 is not allowed by Access-Control-Allow-Origin by sending request to flask

I am sending GET request from localhost:8000 to flask :
$(document).ready(function() {
$('#test').click(function() {
$.getJSON("http://localhost:5000/test/", function() {
}).done(function() {
document.location = "http://localhost:5000";
}).fail(function() {
console.log("server not ready.");
});
});
});
and in "server.py" I am handling GET like:
import app
#server.route('/test/',methods = ['GET'])
def test():
print "in test status check"
return jsonify({'status':'OK'})
However I am getting this error:
XMLHttpRequest cannot load http://127.0.0.1:**5000**/test/. Origin http://127.0.0.1:**8000** is not allowed by Access-Control-Allow-Origin.
In flask you can create custom decorator to control Access Origin Policy. This article may help you: http://flask.pocoo.org/snippets/56/
Code from article:
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
And here is how you can use it:
#app.route('/my_service')
#crossdomain(origin='*')
def my_service():
return jsonify(foo='cross domain ftw')

Resources