building a local web server and respond data to javascript - 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.

Related

FastAPI rejecting POST request from javascript code but not from a 3rd party request application (insomnia)

When I use insomnia to send a post request I get a 200 code and everything works just fine, but when I send a fetch request through javascript, I get a 405 'method not allowed error', even though I've allowed post requests from the server side.
(Server side code uses python).
Server side code
from pydantic import BaseModel
from typing import Optional
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
origins = ["*"]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["POST", "GET"],
allow_headers=["*"],
)
class data_format(BaseModel):
comment_id : int
username : str
comment_body : Optional[str] = None
#app.post('/post/submit_post')
async def sumbit_post(somename_3: data_format):
comment_id = somename_3.comment_id
username = somename_3.username
comment_body = somename_3.comment_body
# add_table_data(comment_id, username, comment_body) //Unrelated code
return {
'Response': 'Submission received',
'Data' : somename_3
}
JS code
var payload = {
"comment_id" : 4,
"username" : "user4",
"comment_body": "comment_4"
};
fetch("/post/submit_post",
{
method: "POST",
body: JSON.stringify(payload),
headers: {
'Content-Type': 'application/json'
}
})
.then(function(res){ return res.json(); })
.then(function(data){ alert( JSON.stringify( data ) ) })
The error
What should I do to get around this error?
Thanks in advance.
To start with, your code seems to be working just fine. The only part that had to be changed during testing it (locally) was the URL in fetch from /post/submit_post to (for instance) http://127.0.0.1:8000/post/submit_post, but I am assuming you already changed that using the domain name pointing to your app.
The 405 Method Not Allowed status code is not related to CORS. If POST was not included in the allow_methods list, the response status code would be 400 Bad Request (you could try removing it from the list to test it). From the reference above:
The HyperText Transfer Protocol (HTTP) 405 Method Not Allowed response
status code indicates that the server knows the request method, but
the target resource doesn't support this method.
The server must generate an Allow header field in a 405 status code
response. The field must contain a list of methods that the target
resource currently supports.
Thus, the 405 status code indicates that the POST request has been received and recognised by the server, but the server has rejected that specific HTTP method for that particular endpoint. Therefore, I would suggest you make sure that the decorator of the endpoint in the version you are running is defined as #app.post, as well as there is no other endpoint with the same path using #app.get. Additionally, make sure there is no any unintentional redirect happening inside the endpoint, as that would be another possible cause of that response status code. For future reference, when redirecting from a POST to GET request, the response status code has to change to 303, as shown here. Also, you could try allowing all HTTP methods with the wildcard * (i.e., allow_methods=['*']) and see how that works (even though it shouldn't be related to that). Lastly, this could also be related to the configurations of the hosting service you are running the application; thus, might be good to have a look into that as well.
It's and old issue, described here. You need Access-Control-Request-Method: POST header in your request.

AJAX Request CORS Policy error with Flask

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.

Flask Session Not Persisting (Postman works, Javascript doesn't)

I'm developing a Flask server to communicate between some backend Python functionality and Javascript clients over the web. I'm attempting to utilize Flask's session variable to store user specific data over the course of their time interacting with the app. I've removed most of the application specific code below but the core problem I'm experiencing remains.
Here is my the code for my (simplified) Flask app:
import json
import os
from flask import Flask, jsonify, request, session
app = Flask(__name__)
app.secret_key = 'my_secret_key'
#app.route('/', methods=['GET'])
def run():
session['hello'] = 'world'
return jsonify(session['hello'])
#app.route('/update', methods=['POST'])
def update():
return jsonify(session['hello'])
if __name__ == '__main__':
app.run(host='0.0.0.0')
Utilizing Postman, I can make a GET request to my server and receive the expected output of "world". I can then make a POST request with an arbitrary body and receive the same expected output of "world" (again using Postman).
When using Chrome, I can visit my server IP and see the expected output "world" on the page. I can also manually make a GET request using Javascript (in Chrome's console) and receive the same response as expected. However, my problem arises when trying to send a POST request to the server using Javascript; the server shows a KeyError: 'hello' when trying to make this request.
Here is the Javascript I'm using to make the POST request:
var url = 'http://my_server_ip/update';
fetch(url, {
method: 'POST',
body: JSON.stringify('arbitrary_string'),
headers: new Headers({
'Content-Type': 'application/json'
})
})
.then(response => response.json())
.then((data) => {
console.log(data);
})
What's going wrong here? Why can I make the GET/POST requests with Postman just fine but run into errors making the same requests with Javascript?
The caveats section of the fetch documentation says:
By default, fetch won't send or receive any cookies from the server, resulting in unauthenticated requests if the site relies on maintaining a user session.
It is recommended to use AJAX to exchange information with Flask views.
Meanwhile, in your code for the Flask app, the session object is a dictionary. Now, if you access a dictionary with its key session['hello'] and if this key does not exist, a Keyerror is raised. To get around this error, you can use the get() method for dictionaries.
What is happening is: the fetch request does not find the hello key(or GET the session value from the Flask view) in the Flask session.
user = session.get('hello')
return jsonify(session_info=user)
But this will still give you a null value for the session { session_info: null }. Why is that so?
When you send GET/POST requests to the Flask server, the session is initialized and queried from within Flask. However, when you send a Javascript fetch POST request, you must first GET the session value from Flask and then send it as a POST request to your Flask view which returns the session information.
In your code, when the POST request is triggered from fetch, when I send the payload data to Flask, it is received correctly and you check this using request.get_json() in the Flask view:
#app.route('/update', methods=['POST'])
def update():
user = session.get('hello')
payload = request.get_json()
return jsonify(session_info=user, payload=payload)
This will return { payload: 'arbitrary_string', session_info: null }. This also shows that fetch does not receive the session information because we did not call GET first to get the session information from Flask.
Remember: The Flask session lives on the Flask server. To send/receive information through Javascript you must make individual calls unless there is a provision to store session cookies.
const fetch = require('node-fetch');
var url_get = 'http://my_server_ip';
var url_post = 'http://my_server_ip/update';
fetch(url_get, {
method:'GET'
}).then((response)=>response.json()).then((data) =>fetch(url_post, {
method: 'POST',
body: JSON.stringify(data),
dataType:'json',
headers: {
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then((postdata) => {
console.log(postdata);
}));
The Flask views will change slightly:
#app.route('/', methods=['GET'])
def set_session():
session['hello'] = 'world'
return jsonify(session['hello'])
#app.route('/update', methods=['POST'])
def update():
payload = request.get_json()
return jsonify(session_info=payload)
When you trigger the Javacript request now, the output will be: { session_info: 'world' }
After a few hours of testing, I managed to figure out the issue. Although I think #amanb's answer highlights the problem, I'm going to answer my own question because what I found is ultimately a simpler solution.
In order to make the POST request return the expected value, I simply needed to add a credentials: 'same-origin' line to the fetch body. This looks like the following:
var url = 'http://my_server_ip/update';
fetch(url, {
method: 'POST',
body: JSON.stringify('arbitrary_string'),
credentials: 'same-origin', // this line has been added
headers: {
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then((data) => {
console.log(data);
})
According to Mozilla's Fetch usage guide,
By default, fetch won't send or receive any cookies from the server,
resulting in unauthenticated requests if the site relies on
maintaining a user session.
So it seems I looked over this. Changing the credentials to allow communication of the cookie/session between client and server resolved the issue.

Python Tornado: how do I set WebSocket headers?

I'm new to web development so let me explain:
I want my Python Tornado server to communicate with a web page. My web page uses WebSockets and the onmessage function to print what it should receive from the Tornado server. Basically, here is the HTML JavaScript part:
$(document).ready(function() {
var myURL = "http://localhost:8888";
var source = new EventSource(myURL, { withCredentials: true }); // Access-Control-Allow-Origin
...
source.onmessage = function(event) {
console.log("received new event!");
};
...
}); // ready()
I'm setting the withCredentials parameter to true so CORS are enabled.
On the Tornado side, I have a WebSocket class which is supposed to answer back, but I don't know how to set the header to have Access-Control-Allow-Origin enabled. Here is the tornado code:
class EchoWebSocket(tornado.websocket.WebSocketHandler):
def check_origin(self, origin):
return True
def on_message(self, message):
self.write_message(u"Received message: " + message)
def make_app():
return tornado.web.Application([ ('/', EchoWebSocket), ])
if __name__ == '__main__':
app = make_app()
app.listen(8888)
print 'listening on port 8888...'
# start main loop
tornado.ioloop.IOLoop.current().start()
I'm stuck with the following error in my browser!
GET http://localhost:8888/ [HTTP/1.1 400 Bad Request 1ms]
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8888/. (Reason: CORS header 'Access-Control-Allow-Origin' missing).
What am I missing???
Your javascript is using EventSource but your server is serving WebSockets. These are two completely different things. You need to change one of those to match the other.

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

Categories

Resources