AJAX Request CORS Policy error with Flask - javascript

I'm using Flask to build a simple backoffice.
I'm trying to make some requests on client-side using AJAX, but it is always throwing me the following error:
access to XMLHttpRequest at 'http://10.11.0.123/...' from origin 'http://localhost:5000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I've already tried several solutions but none of them worked. I'm also using CORS package from flask_cors, in the following way:
CORS(app, resources={r"/hardware/control/1": {"origins": "http://localhost:5000"}})
app.run(host="0.0.0.0", port=5000, threaded=True)
However, I think that have no impact on AJAX requests since Flask app runs on server side. So here it is my ajax request:
$.ajax({
url: 'http://10.11.0.123/...',
type: "GET",
contentType: 'text/plain',
headers: {
'Access-Control-Allow-Origin': '*',
},
withCredentials: true,
crossDomain: true,
success: function (result) {
console.log(result)
},
});
I know that the destination sever is receiving the request, however I can not receive any response from the server.
Analysing the network requests, from chrome console, the request returns status: failed and Type: xhr.
My endpoint in flask is:
#system.route('/hardware/control/<int:device_id>')
def hardware_control(device_id):
device = Device.query.get(device_id)
return render_template('hardware_interaction/camera_preview.html',device=device)
I'm creating the app like this:
def create_app():
app = Flask(__name__, instance_relative_config=False)
app.config.from_object('config.DevelopmentConfig')
CORS(app, resources={r"/hardware/control/*": {"origins": "*"}})
with app.app_context():
return app
app = create_app()
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, threaded=True)

You can use this to test that it's actually a CORS issue. This worked for me.
#app.after_request
def after_request(response):
header = response.headers
header['Access-Control-Allow-Origin'] = '*'
header['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
header['Access-Control-Allow-Methods'] = 'OPTIONS, HEAD, GET, POST, DELETE, PUT'
return response

The header Access-Control-Allow-Origin must be returned from Flask, not requested by AJAX. So it would be something like this:
def get_content():
return "It works!", 200
#app.route('/')
def home():
content, status_code = get_content()
headers = {'Access-Control-Allow-Origin': '*'}
return content, status_code, headers

Thank you all for the help. I already solved the problem. I was making requests to HTTP PTZ Camera which don't let me make requests from client side (I've no idea why). So I hack the problem, and now I'm making requests to my server, and my server make the request to the camera. Here you've what I'm doing:
$.ajax({url: 'http://127.0.0.1:5000/teste00',
type: "GET",
success: function (result) {},
});
On server side:
#system.route('/teste00')
def teste():
response = requests.get('camera_url')
return response.content

There are a time from question, but i use flask-cors
To install using pip:
pip install flask flask-cors
See documentation in https://flask-cors.readthedocs.io/en/latest/
from flask_cors import CORS, cross_origin
app = Flask(__name__)
CORS(app, support_credentials=True)
#app.route('/ajaxcomp')
#cross_origin(supports_credentials=True)
def ajaxcomp():
if request.is_json:
component = request.args.get('component')
comp_list = components.query.filter_by(SIGLA=componente).all()
results = components_schema.dump(comp_list)
return jsonify(results)
For me works fine.

Related

Flask API with CORS error in delete method

I have developed a rest api in Flask. All my api endpoints work fine when I test them with postman.
Now, I am developing an application with Javascript that consumes the resources of my api.
I'm having trouble consuming an endpoint that works with the delete method. Endpoints with get and post work fine, but not the delete method. I get the next CORS error:
Access to fetch at 'http://localhost:5000/contacto' from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
This is my Javascript code:
let data ={id: id};
let url = "http://localhost:5000/contacto";
fetch(url, {
credentials: 'include',
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
.then(res => res.json())
.then(res => {
alert(res.result);
});
On the server side, I use flask_cors. I configure the app with this code:
from flask import Flask, jsonify, request
from flask_cors import CORS
import controllers.userController as userController
app = Flask(__name__)
app.config['CORS_HEADERS'] = 'Content-Type'
#CORS(app)
#CORS(app, resources={r"/*": {"origins": "*"}}, send_wildcard=True)
CORS(app, resources={r"/*": {"origins": "http://127.0.0.1:5500"}})
The path of my service with delete method is this:
#app.route('/contacto', methods = ['DELETE'])
def deleteContacto():
parametros = request.args
id = parametros['id']
result = contactController.eliminar_contacto(id)
response = None
if result == True:
response = jsonify({'result':'Contacto eliminado con éxito'})
else:
response = jsonify({'result':'Error al eliminar el contacto'})
response.headers.add('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS')
return response
I need some help. I have searched and tried many possible solutions but they do not work for me. I'm a bit desperate.
Thanks in advance and regards.
I do this a bit different, but make sure you have this option set to allow delete and options methods:
'Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS'
I add them manually to the response object in flask
resp.headers.add('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS')
CORS should be setting this as a default, but maybe something is misconfigured?
see the docs:
https://flask-cors.readthedocs.io/en/latest/configuration.html

building a local web server and respond data to javascript

I am trying to learn to build a web application, and that application needs data generated from a python script. After googling around. I found this link and it seems that I need to:
write a server side application in Python. Define a URL(route) that runs your script.
in my Javascript code, make an HTTP request to the URL defined in Step 1.
In my java script, I have the following ajax call, I'm not too sure what goes in the url field:
$.ajax({
type: "get",
url: "http://localhost:5000",
cache: false,
async: "asynchronous",
dataType: "text",
success: function (data) {
//console.log(JSON.stringify(data));
console.log("---->" + data);
},
error: function (request, status, error) {
console.log("Error: " + error);
},
});
As for my web server side, I wanted to write it from sockets since I want to learn some socket programing as well, so following another post I wrote my server below, in this server, my goal is to just return a simple string to prove that this works, but ultimately I want to be able to return a json object :
import socket
import threading
import json
import pdb
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('localhost', 5000))
sock.listen(1)
print("Listening at------>>> ", sock.getsockname())
connections = []
# Reply as HTTP/1.1 server, saying "HTTP OK" (code 200).
response_proto = 'HTTP/1.1'
response_status = '200'
response_status_text = 'OK' # this can be random
res_status = "{} {} {}".format(response_proto, response_status,
response_status_text)
response_body_raw = "hello world"
# Clearly state that connection will be closed after this response,
# and specify length of response body
response_headers = {
'Content-Type': 'text; encoding=utf8',
'Content-Length': len(response_body_raw),
'Connection': 'close',
}
response_headers_raw = ''.join('%s: %s\n' % (k, v) for k, v in
response_headers.items())
def handler(c, a):
global connections
while True:
data = c.recv(1024)
print(data)
for connection in connections:
# sending all this stuff
connection.sendall(res_status.encode('utf-8'))
connection.sendall('\n'.encode('utf-8'))
connection.sendall(response_headers_raw.encode('utf-8'))
# to separate headers from body
connection.sendall('\n'.encode('utf-8'))
connection.sendall(response_body_raw.encode('utf-8'))
if not data:
connections.remove(c)
c.close()
break
while True:
c, a = sock.accept()
print("Connected by------->>>", a)
cThread = threading.Thread(target=handler, args=(c, a))
cThread.daemon = True
cThread.start()
connections.append(c)
when I run my website using VS code live server extension, I get the following errors:
Access to XMLHttpRequest at 'http://localhost:5000/?_=1586356660223' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
GET http://localhost:5000/?_=1586356660223 net::ERR_FAILED
I looked into the No 'Access-Control-Allow-Origin' error, and it seems that I cannot provide url as localhost in my ajax call. if not, then what should I put in the url field if I want to talk to my local server?
Add a Access-Control-Allow-Origin to your response header:
response_headers = {
'Access-Control-Allow-Origin': '*',
...
}
So, as already mentioned in my Comment, I used a Flask server to process the POST-Data sent with Ajax.
Basically, you can set up the server like this:
from flask import Flask, requests
app = Flask(__name__)
#app.route("/", methods=['POST', 'GET'])
def main_page():
return "200"
if __name__ == "__main__":
app.run(debug=True, host='192.169.178.62')
with the host='192.169.178.62', you can specify the IP you want to run your Flask app.
I would suggest you find out your Computers IP, and either use that one to run Flask or use an IP in the same network.
In your AJAX, you need to enter this URL to send the request to.
If anything is not working as it should, feel free to contact me.

Request header field Access-Control-Request-Methods is not allowed by Access-Control-Allow-Headers in preflight response

I'm trying to send a POST request from my website to my remote server but I encounter some CORS issues.
I searched in the internet but didn't find a solution to my specific problem.
This is my ajax request params:
var params = {
url: url,
method: 'POST',
data: JSON.stringify(data),
contentType: 'json',
headers: {
'Access-Control-Request-Origin': '*',
'Access-Control-Request-Methods': 'POST'
}
On the backend side in this is my code in python:
#app.route(SETTINGS_NAMESPACE + '/<string:product_name>', methods=['POST', 'OPTIONS'])
#graphs.time_method()
def get_settings(product_name):
settings_data = helper.param_validate_and_extract(request, None, required=True, type=dict, post_data=True)
settings_data = json.dumps(settings_data)
response = self._get_settings(product_name, settings_data)
return output_json(response, requests.codes.ok, headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST'
})
I get an error on my console:
XMLHttpRequest cannot load [http://path-to-my-server]. Request header field
Access-Control-Request-Methods is not allowed by
Access-Control-Allow-Headers in preflight response
I did notice that I can add also 'Access-Control-Request-Headers' but I wasn't sure if it necessary and it cause me more problems so I removed it.
Does anyone know how to solve this problem?
Your ajax request shouldn't send Access-Control headers, only the server sends those headers to allow the servers to describe the set of origins that are permitted to read that information using a web browser.
The same-origin policy generally doesn't apply outside browsers, so the server has to send CORS headers or JSONP data if the browser is going to be able to get the data.
The browser doesn't send those headers to the server, it doesn't have to, it's the server that decides whether or not the data is available to a specific origin.
Remove the header option from the params object, and it should work

Add CORS header to an http request using Ajax

I have developed a Restfull application and I'd like to add another web application to consume its services so I make this Ajax call :
$.ajax({
type: "Post",
async: false,
url: "ip_adress/Inviter/api/Account/Register",
data: donne,
headers: { "Access-Control-Allow-Origin:": "*"},
success: function (data) {
console.log(data);
var tab = [];
tab["username"] = username;
tab["password"] = pwd;
var isLogged = Login.CheckCredential(tab, username);
return isLogged;
},
error: function (xhr, status, error) {
console.log(xhr);
console.log(status);
console.log(error);
}
});
I get this exception :
Object {readyState: 0, status: 0, statusText: "SyntaxError: Failed to
execute 'setRequestHeader' …-Origin:' is not a valid HTTP header
field name."} error DOMException: Failed to execute 'setRequestHeader'
on 'XMLHttpRequest': 'Access-Control-Allow-Origin:' is not a valid
HTTP header field name.
So I need to know :
How can I enable the CORS in this situation?
How can I fix my code?
You can't authorize yourself like that. It's a response header; details in the specification. The server you're sending the request to has to send that header back to let the browser know it's okay to allow your page to send an ajax request to that server. There's nothing you can do in your client-side code if the server you're trying to request from doesn't allow your origin.
somehow i redirected to this question to get the solution for my Flask application. Since the server has to send the response back to the header, the CORS has to set in the server side.
In my case i was trying to send the request from
client
http://127.0.0.1:8081/
to
server
http://127.0.0.1:5051
So i set the cors policy to allow the origin in the client side
headers: { "Access-Control-Allow-Origin:": "*"},
and for the server side, flask provides library to allow the cors
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
it actually got resolved the issue

Why is successful jQuery cross domain post request not firing success handler?

I am making the following JQuery cross domain ajax post request from a phonegap (appgyver steroids) app.
function do_something(callback_method, some_vars)
{
var stringified_some_vars = JSON.stringify(some_vars);
$.ajax({
type: "POST",
url:"http://www.somedomain.com/endpoint",
data: {'some_vars' : stringified_some_vars},
async: true,
dataType: 'json',
crossDomain: true,
xhrFields: {
withCredentials: true
},
success: function(result)
{
var myObject = $.parseJSON(result);
callback_method(myObject);
},
error: function(fail)
{
supersonic.logger.debug(fail);
}
});
}
The post request is successfully sent to the server (Google Appengine - Python) - i.e. the server fires the relevant method. However, when the server response is received the jQuery Ajax method doesn't fire the success handler - it instead fires the error handler. The error text prints to console as
{"readyState":0,"responseText":"","status":0,"statusText":"error"}
The headers in the json response from the server are as follows:
Content-Length: 0
Cache-Control: no-cache
Access-Control-Allow-Origin: *
Content-Type: application/json
the content of the response is as expected. and is written using
text_to_send = json.dumps(python_dict)
self.response.headers.add_header('Access-Control-Allow-Origin', '*')
self.response.headers['Content-Type'] = 'application/json'
self.response.write(text_to_send)
It's not clear to me where this error is coming from. Allowing cross domain requests doesn't seem to have fixed the issue. jsonp GET requests work fine - but obviously these aren't allowed for POST requests. Could anyone tell me where I'm going wrong?
Edit 1
Following the suggestion of #Faisal I adjusted the server code as follows
from urlparse import urlparse
uri = urlparse(self.request.referer)
origin = '{}://{}'.format(uri.scheme, uri.netloc)
self.response.headers.add_header('Access-Control-Allow-Origin', origin)
self.response.headers['Content-Type'] = 'application/json'
The headers are now
Content-Length: 0
Cache-Control: no-cache
Access-Control-Allow-Origin: http://localhost
Content-Type: application/json
However the same error is encountered
I think if it's withCredentials: true you need your origin to be exact match instead of wildcard (*). Here is a quick code to get it from referer. But you should probably also check if its one of the allowed origins:
from urlparse import urlparse
uri = urlparse(self.request.referer)
origin = '{}://{}'.format(uri.scheme, uri.netloc)
Edit
Try adding:
self.response.headers.add_header('Access-Control-Allow-Credentials', 'true')

Categories

Resources