Adding external javascript to page that will be sent by a server - python

I'm building a little server that sends a page with a script in javascript, it works when I try to open it in my browser, but if I request the page from the server, the page is recived, but not the script, so I get these errors:
Script.js is missing between the files:
Looks strange because from the network session i can see a request for the script with the status 200:
The js file i'm tryng to add is Chart.js, so I can't add it internally, it would become impossible to work with it, but for now the server is just a few lines of code in python that use the SimpleHTTPRequestHandler, and I'm probably going to replace it, may it be because the SimpleHTTPRequestHandler can't handle multiple file requests?
Here's the code, tried to make a snippet but it does't work there too (probably that's just me never wrote a snippet before):
HTML:
<!doctype html>
<html>
<head>
<script src="script.js"></script>
</head>
<body>
<p id = "paragraph"></p>
<script>
document.getElementById('paragraph').innerHTML = sayHello();
</script>
</body>
</html>
JS:
function sayHello(){
return "HelloWorld!"
}
Here is the python server script:
from http.server import HTTPServer, BaseHTTPRequestHandler
class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.end_headers()
with open("index.html", "r") as page:
self.wfile.write(page.read())
httpd = HTTPServer(("192.168.1.100", 8000), SimpleHTTPRequestHandler)
httpd.serve_forever()

I think you get an element with id, tag name or class Name and add file
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.onload = function() {
callFunctionFromScript();
}
script.src = 'path/to/your-script.js';
head.appendChild(script);
also check this link

Related

How to prevent Flask (python) from emitting html?

It appears that Flask assumes that the server is returning html to the client (browser).
Here's a simple example;
import json
from flask import Flask
app = Flask(__name__)
#app.route("/")
def home():
msg = ['Hello, world!']
return json.dumps(msg) + '\n'
This code works as expected and returns the desired json;
$ curl -s http://localhost:5000/
["Hello, world!"]
But if I introduce an error;
import json
from flask import Flask
app = Flask(__name__)
#app.route("/")
def home():
msg = ['Hello, world!']
return json.dumps(XXmsg) + '\n'
Then Flask emits the error wrapped in several pages worth of html, starting like;
$ curl -s http://localhost:5000/
<!DOCTYPE html>
<html>
<head>
<title>NameError: name 'XXmsg' is not defined
// Werkzeug Debugger</title>
<link rel="stylesheet" href="?__debugger__=yes&cmd=resource&f=style.css">
<link rel="shortcut icon"
href="?__debugger__=yes&cmd=resource&f=console.png">
<script src="?__debugger__=yes&cmd=resource&f=debugger.js"></script>
<script>
var CONSOLE_MODE = false,
EVALEX = true,
EVALEX_TRUSTED = false,
SECRET = "Mq5TSy6QE4OuOHUfvk8b";
</script>
</head>
<body style="background-color: #fff">
<div class="debugger">
Emitting html makes sense if you're creating a page load app. But I'm creating an api that only returns json.
Is there anyway to prevent Flask from emitting html at all?
Thanks
Mike
Have a look at the section Returning API Errors as JSON of the Flask docs.
Basically, you have to replace the default error handler with a function that returns the error as json. A very basic example:
#app.errorhandler(HTTPException)
def handle_exception(exception):
response = exception.get_response()
response.content_type = "application/json"
response.data = json.dumps({"code": exception.code})
return response
The accepted response gives a good hint for handling HTTPException but it won't work for all exceptions unless you create a handler for the mother of all exceptions:Exception. And you might not want to do this for security reasons, if you have some custom defined exceptions with sensible data it'll get handled by this handler.
I suspect the true reason you have those lengthy html responses is because you started your flask app with the --debug option.

Update Flask web page with python script

Program description: I already have a functioning program that runs on console window, but I'd like to present its output on a locally hosted web page. The program consists on getting lyrics for currently playing songs by making requests to Spotify's API. I store the current lyrics in a "lyrics.txt" file.
What I want:
Change the web page from the running lyrics program when it detects the song has changed.
[EDIT:]
Is there a way to make the flask page display a variable, that is updated by a python request.post of the lyrics app to the flask url with the updated variable as the data?
What I have:
I'm using Flask as the framework since its a one local web page.
import os, io
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
def test():
'''reads the current lyrics file and passes it to the web page
manually reload the page to update lyrics'''
with io.open('lyrics.txt', 'r') as f:
HEAD = f.readline().strip("\n")
BODY = f.read().split('\n')
lyrics = {"HEAD": HEAD, "BODY": BODY}
return render_template("home.html", lyrics=lyrics)
if __name__ == "__main__":
app.run(debug=1)
link to lyrics app github
You would need JavaScript/AJAX on page which periodically sends request for new content and Flask should send current content from file.
In this example I use jQuery.get() to send request to server, and setTimeout() to repeat it periodically.
Flask sends current time to show different content.
import datetime
from flask import Flask, render_template_string
app = Flask(__name__)
#app.route("/")
def index():
return render_template_string("""<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Test</title>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.8.0.min.js"></script>
<script type="text/javascript">
function updater() {
$.get('/data', function(data) {
$('#time').html(data); // update page with new data
});
};
setInterval(updater, 1000); // run `updater()` every 1000ms (1s)
</script>
</head>
<body>
Date & Time: <span id="time"><span>
</body>
</html>""")
#app.route('/data')
def data():
"""send current content"""
return datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
if __name__ == "__main__":
app.run(debug=True)
EDIT:
The same using standard fetch() without external libraries.
Code has to be after <span>
import datetime
from flask import Flask, render_template_string
app = Flask(__name__)
#app.route("/")
def index():
return render_template_string("""<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Test</title>
</head>
<body>
Date & Time: <span id="time"><span>
<script type="text/javascript">
var time_span = document.getElementById("time");
function updater() {
fetch('/data')
.then(response => response.text())
.then(text => (time_span.innerHTML = text)); // update page with new data
}
setInterval(updater, 1000); // run `updater()` every 1000ms (1s)
</script>
</body>
</html>""")
#app.route('/data')
def data():
"""send current content"""
return datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
if __name__ == "__main__":
app.run(debug=True)

Problems with receiving 'utf-8' from client

I am trying to create a 2-way communication between server and client using Flask and socket.io.
Everything works fine until server receives utf-8 string from client, which gets garbled. Sending from server to client works fine, and prior to sending from client to server, the client prints the message correctly.
Here is some code that reproduces the problem:
app.py:
import flask
from flask_socketio import SocketIO, emit, disconnect
import json
app = flask.Flask(__name__)
socket_io = SocketIO(app)
#socket_io.on('pull')
def socket_io_handle_pull():
json_msg = {
'msg': "abcćčddžđefghijklmnnjoprsštuvzž"
}
print("Pushing", json_msg)
socket_io.emit('response', json_msg)
#socket_io.on('push')
def socket_io_handle_push(json_msg):
print("Pushed:", json_msg)
#socket_io.on('disconnect')
def socket_io_handle_disconnect():
disconnect()
#app.route('/')
def root():
return flask.render_template(
'index.html'
)
if __name__ == '__main__':
socket_io.run(app)
index.html:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script>
</head>
<body>
<script type="text/javascript">
var socket = io.connect('http://' + document.domain + ':' + location.port);
socket.on('response', json => {
socket.emit('push', json);
})
socket.emit('pull');
</script>
</body>
</html>
Output:
Pushing {'msg': 'abcćčddžđefghijklmnnjoprsštuvzž'}
Pushed: {'msg': 'abcÄ\x87Ä\x8dddA3Ä\x91efghijklmnnjoprsA!tuvzA3'}
You are using the 1.x versions of the Socket.IO client, which had known problems with double-encoding of UTF-8 strings. You should try the 2.x versions which have resolved this issue.
It seems that I was getting back a mojibake decoded using latin-1 and encoded with utf-8.
To fix this, I added:
json_str = json_str.encode('latin-1').decode('utf-8')
If you are having this problem, take a look at Miguel's answer.
I used servers socket.io js file from reverse proxy by adding socket.io.js end of reverse proxy path like this xxx.com/reverse_proxy_path/socket.io

Python HTTP server, can't use images

What I've done:
I've created a small HTTP server python, using no modules but socket. It manages to start, load HTML and then send it out,
so you can see the HTML file in your browser.
What I'm using:
I'm using Python 3.5.1, I'm also using Socket.
The problem:
Images do not show on the web browser.
Here is the code I have put together:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
HOST = ''
PORT = 8888
asked_url = []
s.bind((HOST, PORT))
s.listen(1)
while True:
conn, addr = s.accept()
request = conn.recv(1024)
html_file = open("page.html", 'rb')
try:
http_response = html_file.read()
conn.sendall(http_response)
conn.sendall(b'<p><small>PyWeb</small></p>')
except:
print("Couldn't send any data! Passing...")
pass
conn.close()
Here is also the HTML code for the page, However it doesn't seem to be the problem:
<script src="https://mcapi.us/scripts/minecraft.js"></script>
<div class="server-status">
My awesome server is currently <span class="server-online"></span>!
</div>
<script>
MinecraftAPI.getServerStatus('SERVER HERE', {
port: 25565 // optional, only if you need a custom port
}, function (err, status) {
if (err) {
return document.querySelector('.server-status').innerHTML = 'Error loading status';
}
// you can change these to your own message!
document.querySelector('.server-online').innerHTML = status.online ? 'up' : 'down';
});
</script>
<img src="test.png" alt="Test Image" style="width:304px;height:228px;">
What the HTML code does:
Shows text and an image.
If you need more detail just ask.
Where is test.png located? Looks like your HTML is having an issue finding the file. I ran your code locally and was able to see an image when I changed to image tag to source an image from a url.
I checked chrome dev tools first and noticed the image tag rendered fine.
I changed the image tag to (random image from google image search):
`<img src="http://emojipedia-us.s3.amazonaws.com/cache/f8/69/f869f6512b0d7187f4e475fc9aa7f250.png" alt="Test Image">`
And it showed up fine.
The issue is that no matter what the request you get to your HTTP server you are sending the content of page.html as response. This is because you hard coded this line in your server.
html_file = open("page.html", 'rb')
In your page.html you have an image that means browser (or any client that you use) will send a call to your server asking for image's source (content of test.png) but instead of reading the image's source you are again serving page.html's content. That is why the image appears broken.
To fix this you need to look at the resource that is requested and open that file and send the content as response from server. Take a look at what you have in request variable in your server code to get an idea of how you can get the name of the resource requested.
You might also want to send out the proper content-type header to let the client know how it has to handle the response.

web.py doesn't find file

I try to create a little website using web.py and webpysocketio, and I have a problem: Web.py doesn't seem to find any file besides the index.html.
Here's my webpy app:
import web
from socketio import SocketIOServer
from gevent import monkey
monkey.patch_all()
from webpy_socketio import *
urls = (
'/', 'index',
)
urls += socketio_urls
app = web.application(urls, globals())
SOCKETIO_HOST = ""
SOCKETIO_PORT = 8080
application = app.wsgifunc()
if __name__ == "__main__":
SocketIOServer((SOCKETIO_HOST, SOCKETIO_PORT), application, resource="socket.io").serve_forever()
class index:
def GET(self):
render = web.template.render('templates/')
return render.index()
#on_message(channel="my channel")
def message(request, socket, context, message):
socket.send_and_broadcast_channel(message)
In my template folder I have the index.html (and the socketio_scripts.html):
<html>
<head>
<meta charset="utf-8">
<title>webpysocketio TEST</title>
<object type="text/html" data="socketio_scripts.html">
<script>
var socket = new io.Socket();
socket.connect();
socket.on('connect', function() {
socket.subscribe('my channel');
socket.send('asdf');
});
</script>
</object>
</head>
<body>
<div>
</div>
</body>
</html>
Now when I run the webiste, after I visit it in a browser, I get the following on my terminal:
IP - - [DATE] "GET /socketio_scripts.html HTTP/1.1" 404 135 0.004273
Why does it not find the other html file?
I suspect that /socketio_scripts.html is not the correct url for that file - it seems odd that that file would be at the root of your document tree.
According to several pages, it should be in .../templates/. I also doubt very much it would ever be accessed by GET
Have a look at the web.py tutorial. One big difference with your code is that all the pages have to be listed in the urls dispatch table:
urls = (
'/', 'hello',
'/bye', 'bye')
The static files which you dont want to be served from GET function have to be placed in a static file , in your example the "socketio_scripts.html"
and accessed by the full url "http://localhost/static/socketio_scripts.html". http://webpy.org/cookbook/staticfiles

Categories