I am trying to upload many files at once to my CherryPy server.
I am following this tutorial that shows PHP code on the server side.
The JavaScript part is simple. Here is a summary of what it does:
function FileSelectHandler(e) {
var files = e.target.files || e.dataTransfer.files;
for (var i = 0, f; f = files[i]; i++) {
var xhr = new XMLHttpRequest();
xhr.open("POST", "upload", true);
xhr.setRequestHeader("X_FILENAME", file.name);
xhr.send(file);
}
I translated the upload.php described in the tutorial into something like this:
def upload(self):
[...]
When the server receives the request I can see that cherrypy.request.headers['Content-Length'] == 5676
which is the length of the file I'm trying to upload, so I assume the whole file has been sent to the server.
How do I get the content of the file?
At its minimum it looks like the following. Tested in Firefox and Chromium. If you need to support legacy browsers I'd look at some JavaScript library for polyfills and fallback.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import shutil
import cherrypy
config = {
'global' : {
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 8,
}
}
class App:
#cherrypy.expose
def index(self):
return '''<!DOCTYPE html>
<html>
<head>
<title>CherryPy Async Upload</title>
</head>
<body>
<form id='upload' action=''>
<label for='fileselect'>Files to upload:</label>
<input type='file' id='fileselect' multiple='multiple' />
</form>
<script type='text/javascript'>
function upload(file)
{
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', function(event)
{
console.log('progess', file.name, event.loaded, event.total);
});
xhr.addEventListener('readystatechange', function(event)
{
console.log(
'ready state',
file.name,
xhr.readyState,
xhr.readyState == 4 && xhr.status
);
});
xhr.open('POST', '/upload', true);
xhr.setRequestHeader('X-Filename', file.name);
console.log('sending', file.name, file);
xhr.send(file);
}
var select = document.getElementById('fileselect');
var form = document.getElementById('upload')
select.addEventListener('change', function(event)
{
for(var i = 0; i < event.target.files.length; i += 1)
{
upload(event.target.files[i]);
}
form.reset();
});
</script>
</body>
</html>
'''
#cherrypy.expose
def upload(self):
'''Handle non-multipart upload'''
filename = os.path.basename(cherrypy.request.headers['x-filename'])
destination = os.path.join('/home/user', filename)
with open(destination, 'wb') as f:
shutil.copyfileobj(cherrypy.request.body, f)
if __name__ == '__main__':
cherrypy.quickstart(App(), '/', config)
Related
I have a flask and Python application where I have a Templates directory to hots an index.html
that I render using
#app.route("/")
def home():
return render_template('index.html')
that works fine , but the web page index.html uses jquery to read a json file and for some reason it cannot read it in the FLASK webserver environment
the json file is in a folder called ./curldata and the rendered html file is in a folder ./Templates at the same level
the error I get in developer tools ie:
jquery-3.5.0.js:10099 GET http://127.0.0.1:5000/curldata/views.json 404 (NOT FOUND)
send # jquery-3.5.0.js:10099
ajax # jquery-3.5.0.js:9682
jQuery.<computed> # jquery-3.5.0.js:9836
getJSON # jquery-3.5.0.js:9817
(anonymous) # (index):6
(anonymous) # (index):18
see index.html below:
<html>
<head>
<script src="https://code.jquery.com/jquery-3.5.0.js"></script>
<script>
(function() {
$.getJSON( "../curldata/views.json", function( data ) {
var items = [];
$.each( data, function( key, val ) {
items.push( "<li><a href='" + val + "'>" + val + "</a></li>" );
});
$( "<ul/>", {
"class": "my-new-list",
html: items.join( "" )
}).appendTo( "body" );
});
})();
</script>
</head>
<body>
BODY:</br>
</body>
</html>
I am an idiot , first off I am embedding the front end in the backend
then I was'nt even using the backend
$.getJSON( "/views", function( data ) {
changing this line is the answer since the flask server is providing the json
sorry about that
I just learn flask to use with jquery, just want to print out what i typed in , but it print nothing
here is html code
<body>
<input id="name-input" type="text" />
<button id="name-button">Submit Name</button>
<p id="greeting"></p>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
$("#name-button").click(function (event) {
let message = {
name: $("#name-input").val()
}
$.post("http://10.0.0.4:5000/hello", JSON.stringify(message), function (response) {
$("#greeting").text(response.greeting);
console.log(response);
});
});
</script>
</body>
here is flask code:
from flask import request
from flask import jsonify
from flask import Flask
app = Flask(__name__)
#app.route('/hello',methods=['POST'])
def hello():
message = request.get_json(force=True)
name = message['name']
response = {
'greeting': 'Hello, ' + name + '!'
}
return jsonify(response)
when i click button, it print nothing!. please help, thank a lot
Two issues:
You're using the IP address shown in the example, which is very unlikely to point to your own PC on a network. More likely is 127.0.0.1:5000/hello, which would be localhost if you're running through the dev server. You can actually run the server across the network by providing the --host=0.0.0.0 flag to flask run. NOTE: This is only for the development server; you'll want to look at deployment options when you run this for real
Your route only accepts POST requests, but you're sending a GET request
The HTMl:
<body>
<input id="name-input" type="text" />
<button id="name-button">Submit Name</button>
<p id="greeting"></p>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
$("#name-button").click(function (event) {
let message = {
name: $("#name-input").val()
}
$.post("http://127.0.0.1:5000/hello", JSON.stringify(message), function (response) {
$("#greeting").text(response.greeting);
console.log(response);
});
});
</script>
</body>
The route:
#app.route('/hello',methods=['GET', 'POST'])
def hello():
message = request.get_json(force=True)
name = message['name']
response = {
'greeting': 'Hello, ' + name + '!'
}
return jsonify(response)
I have an ajax js function:
if (data.result == "Successfully joined"){
window.location.href='{{ url_for( 'chat', name = "test" ) }}';
}
and function in python:
#app.route('/chat/<string:name>')
def chat(name):
return render_template("chat.html", c=name, s="Janek")
but when my first (ajax js) is called, it results with 404 not found error. After removing additional variable name, everythink loads corectly. What am I doing wrong?
EDIT 1
the entire js is:
<script type=text/javascript>
$(function() {
$('a#join_btn').bind('click', function() {
$.post('/', {
var1: $('input[name="cname"]').val(),
}, function(data) {
$('#result').text(data.result);
if (data.result == "Successfully joined"){
window.location.href='{{ url_for( 'chat', name = "test" ) }}';
}
});
return false;
});
});
</script>
SOLVED:
adding methods=["POST"] to #app.route('/') fixed the error for me.
#app.route('/chat/<string:name>') should be #app.route('/chat/<name>')
I am currently working on a project from home where I have a network of Arduino's sending data (temp humidity etc.) to a raspberry pi. I want to make the rasp take the data and using plotly make a variety of graphs and then embed said graphs into a website that automatically updates at a set interval. I already have the network up and running I am just stuck on how to get the graphs on to a HTML page and have it update. I was considering just running a Python script that makes a webpage and re-write it with the new graphs every time. This seems highly inefficient so I was wondering if there was a better way of doing it?
Some time ago I had a very similar problem. A very simple solution was to use Python3's http.server to return a JSON with a time stamp and the temperature.
# !/usr/bin/env python3
from http.server import HTTPServer, BaseHTTPRequestHandler
import random
import json
import time
def send_header(BaseHTTPRequestHandler):
BaseHTTPRequestHandler.send_response(200)
BaseHTTPRequestHandler.send_header('Access-Control-Allow-Origin', '*')
BaseHTTPRequestHandler.send_header('Content-type:', 'application/json')
BaseHTTPRequestHandler.end_headers()
class MyRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
# returns the temperature
if self.path == '/temperature':
send_header(self)
self.wfile.write(bytes(json.dumps({'time': time.strftime('%H:%M:%S', time.gmtime()), 'temperature': random.randint(0, 100)}), 'utf-8'))
if __name__ == '__main__':
# start server
server = HTTPServer(('', 8099), MyRequestHandler)
server.serve_forever()
The data is then received via simple vanilla JavaScript and put into plotly. Every 1000 ms a request is sent to the server and the graph is updated accordingly.
<html>
<head>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<script>
var temperatures;
var temperatures_x = [];
var temperatures_y = [];
var server_url = "";
//basic request handler
function createRequest() {
var result = null;
if (window.XMLHttpRequest) {
// FireFox, Safari, etc.
result = new XMLHttpRequest();
if (typeof result.overrideMimeType != "undefined") {
result.overrideMimeType("text/xml"); // Or anything else
}
} else if (window.ActiveXObject) {
// MSIE
result = new ActiveXObject("Microsoft.XMLHTTP");
}
return result;
}
//gets the temperature from the Python3 server
function update_temperatures() {
var req = createRequest();
req.onreadystatechange = function () {
if (req.readyState !== 4) {
return;
}
temperatures = JSON.parse(req.responseText);
return;
};
req.open("GET", server_url + "/temperature", true);
req.send();
return;
}
//updates the graph
function update_graph() {
update_temperatures();
temperatures_x.push(temperatures.time)
temperatures_y.push(temperatures.temperature)
Plotly.newPlot('graph_t', [{x: temperatures_x, y: temperatures_y}]);
}
//initializes everything
window.onload = function () {
document.getElementById("url").onchange = function () {
server_url = document.getElementById("url").value;
};
server_url = document.getElementById("url").value;
//timer for updating the functions
var t_cpu = setInterval(update_graph, 1000);
};
</script>
</head>
<body>
<li>
URL and port<input type="text" id="url" value="http://localhost:8099">
</li>
<div class="plotly_graph" id="graph_t"></div>
</body>
</html>
In the following python/html script,I want to refresh the web page automatically when the value of the variable "condition" equal to "1". So that the page show me the new text contains of the variable "myText" automatically. The variable "myText" can have any text, and the following script is just an example.
#!/usr/bin/python
import cherrypy
import os.path
import struct
from auth import AuthController, require, member_of, name_is
import subprocess
import commands
class Server(object):
led_logout=0
led_restart=0
condition=0
_cp_config = {
'tools.sessions.on': True,
'tools.auth.on': True
}
auth = AuthController()
#cherrypy.expose
#require()
def index(self,logout=''):
html = """
<html>
<head>
</head>
<body>
<p>{htmlText}
<p>
<img src="images/Logout.png">
</ul>
</body>
</html>
"""
myText = ''
myText = "Hello"
if logout:
self.led_logout = int(logout)
if self.led_logout:
print "Logout !!!!!"
AuthController().logout('/?logout=0')
return html.format(htmlText=myText)
index.exposed = True
#configuration
conf = {
'global' : {
'server.socket_host': '0.0.0.0', #0.0.0.0 or specific IP
'server.socket_port': 8085 #server port
},
'/images': { #images served as static files
'tools.staticdir.on': True,
'tools.staticdir.dir': os.path.abspath('/home/ubuntu/webserver/images')
}
}
cherrypy.quickstart(Server(), config=conf)
Ok for you to get your text from the server you're going to need some ajax.
Give this a try...
#!/usr/bin/python
import cherrypy
import os.path
import struct
from auth import AuthController, require, member_of, name_is
import subprocess
import commands
class Server(object):
led_logout=0
led_restart=0
condition=0
_cp_config = {
'tools.sessions.on': True,
'tools.auth.on': True
auth = AuthController()
#cherrypy.expose
#require()
def index(self):
html = """
<html>
<head>
</head>
<body>
<script language="javascript" type="text/javascript">
function getMyText()
{
// code for IE7+, Firefox, Chrome, Opera, Safari
if(window.XMLHttpRequest)
xmlhttp=new XMLHttpRequest();
else// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById('message').innerHTML= = xmlhttp.responseText;
}
}
xmlhttp.open("GET","/getMyText?logout=True", true);
xmlhttp.send();
}
</script>
<p id="message"><p>
<img src="images/Logout.png">
</ul>
</body>
</html>
"""
def getMyText(logout=False)
myText = "Hello"
if logout:
self.led_logout = int(logout)
if self.led_logout:
print "Logout !!!!!"
AuthController().logout('/?logout=0')
return myText
index.exposed = True
#configuration
conf = {
'global' : {
'server.socket_host': '0.0.0.0', #0.0.0.0 or specific IP
'server.socket_port': 8085 #server port
},
'/images': { #images served as static files
'tools.staticdir.on': True,
'tools.staticdir.dir': os.path.abspath('/home/ubuntu/webserver/images')
}
}
cherrypy.quickstart(Server(), config=conf)
Hope this helps!
Andrew