I'm relatively new to Python. I am trying to run a simple server using python. I successfully did this, but I want to have a message such as "Hello World" when I run the server from my browser.
It posts my directory when I run the program and says "Directory listing for/" at the top. Is there a way to add more text on this page?
How would I do this?
import sys
import BaseHTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
HandlerClass = SimpleHTTPRequestHandler
ServerClass = BaseHTTPServer.HTTPServer
Protocol = "HTTP/1.0"
if sys.argv[1:]:
port = int(sys.argv[1])
else:
port = 8000
server_address = ('127.0.0.1', port)
HandlerClass.protocol_version = Protocol
httpd = ServerClass(server_address, HandlerClass)
sa = httpd.socket.getsockname()
print "Serving HTTP on", sa[0], "port", sa[1], "..."
httpd.serve_forever()
When you implement such a httpserver and browse it, the do_GET method of the SimpleHTTPRequestHandler is called. And by default it will searches the directory your script is in for index.html or index.htm. If there is no such file, the directory will be displayed.
So if you want to display contents rather than the directory. You should add a file index.html or index.htm in your directory. And writes the contents you want to display in the file.
For more please refer the doc.
You are using SimpleHTTPServer, and while its great, you would have to use CGI for interaction. This answer does not answer your exact question, but I believe it will allow you to do the same with, with ease.
In Python, we use WSGI servers to interact with websites. The reason we do this, is because WSGI scales and can handle a lot more than CGI or Common Gateway Interface. You can take a look # WSGI, here.
Armin Ronacher wrote this, and he is the author of two popular Python frameworks, Flask and Werkzueg. If you intend to continue learning Python web development, you will meet these frameworks soon.
I realize that this does not answer your question per-se. But, it will allow you to get the same thing, and will give you a foundation that can help you with popular frameworks.
Related
(First time)
I used python -m SimpleHTTPServer 8000 using python 2.7.15 to generate a web server for my simple JavaScript game (still learning), but it seems that it has some error, which makes the canvas of my HTML file wont show.
The JavaScript works totally fine in my GitHub page, but it won't show in local web server. https://jcloh98.github.io/jsgame/simplegame2.html
All the codes are exactly the same as the website. That's all the code I used.
This is the error showed in the console log.
Failed to load module script: The server responded with a non-JavaScript MIME type of "text/plain". Strict MIME type checking is enforced for module scripts per HTML spec.
https://jcloh98.github.io/jsgame/simplegame2.html
It is expected to show a black canvas with a aqua paddle at the bottom of the canvas, like https://jcloh98.github.io/jsgame/simplegame2.html
Instead of using python -m SimpleHTTPServer 8000, create a .py file named "localhost.py" and run the .py file in the same directory of the webpage.
localhost.py force the file with extension ".js" has "application/javascript" as the content type.
localhost.py
#Use to create local host
import SimpleHTTPServer
import SocketServer
PORT = 8000
Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
Handler.extensions_map.update({
".js": "application/javascript",
});
httpd = SocketServer.TCPServer(("", PORT), Handler)
print "Serving at port", PORT
print(Handler.extensions_map[".js"])
httpd.serve_forever()
Thanks Bergi for helping me to solve this problem out.
I am taking a python course where they use BaseHTTPServer. The code they start with is here
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
class webServerHandler(BaseHTTPRequestHandler):
def do_GET(self):
try:
if self.path.endswith("/hello"):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
message = ""
message += "<html><body>Hello!</body></html>"
self.wfile.write(message)
print message
return
except IOError:
self.send_error(404, 'File Not Found: %s' % self.path)
def main():
try:
port = 8080
server = HTTPServer(('', port), webServerHandler)
print "Web Server running on port %s" % port
server.serve_forever()
except KeyboardInterrupt:
print " ^C entered, stopping web server...."
server.socket.close()
if __name__ == '__main__':
main()
I am using python anywhere and there the only possibility to get an application onto the internet is to use an wsgi interface.
A configuration file for the wsgi interface looks like this:
import sys
path = '<path to app>'
if path not in sys.path:
sys.path.append(path)
from app import application
application could be something like this:
def application(environ, start_response):
if environ.get('PATH_INFO') == '/':
status = '200 OK'
content = HELLO_WORLD
else:
status = '404 NOT FOUND'
content = 'Page not found.'
response_headers = [('Content-Type', 'text/html'), ('Content-Length', str(len(content)))]
start_response(status, response_headers)
yield content.encode('utf8')
HELLO_WORLD would be a string with html content.
I cannot just point to port 8080 as in the example. In order to use python anywhere I do have to interface both. I reckoned it could be possible that the wsgi is derived from BaseHTTPServer so it might be possible to interface them and to use my course on pythonanywhere.com
It is clear I have to get rid in the code in the main function and use the application function instead. But I am not exactly getting how this works. I get a callback (start_response) which I call and then I yield the content? How can I combine this with the webServerHandler class?
If this would be possible it should in theory work as well for the google app engine. I found a very complex example here where BaseHTTPServer is used but this is too complex for me yet.
Is it possible to do this and if yes could someone give me a hint how to do this and provide me with some basic start code?
So WSGI is a specification that defines an interface between a request and a webapp. ie. when it receives a http request, it will pass it along to the webapp in a standardized way as described in the specification (eg: it must set this environment variable, it must pass this argument, it must make this call etc).
On the other hand, BaseHTTPServer both defines an interface and also has code that actually serves web requests.
This is a little used interface that is implemented almost exclusively by SimpleHTTPServer from the python2 standard library (or http.server in python3), and the server is not intended for anything production-ready.
This is because SimpleHTTPServer was designed mainly for developing locally. For example, it helps you get past js cross origin request problems when testing on localhost.
Nowadays, WSGI has become the de facto standard for python webapps, and so most websites written in python separate out the server / interface-y functionality that receives and implements the WSGI requirements from the webapp-y stuff.
In your code, you have a single piece of code that does both the "webapp-y" stuff and also the "process the http request / interface-y" stuff. This is not wrong, and is great for getting some basic understanding of how servers process http requests etc.
So my suggestion would be:
if your class is going to start using any python webapp frameworks soon anywahs, (eg: django, flask, , bottle, web2py, cherrypy etc), then you could potentially just wait till then to use pythonanywhere.
if your class is focused on digging into the nitty gritty of servers, you could refactor out the "webapp-y" layer from your code, and just use the "webapp-y" layer on PythonAnywhere. Locally, you would start the "server/interface-y" stuff that then imports your "webapp-y" to generate a response. If you successfully do this, then congrats! You have (kind of) just written a server that supports WSGI.
I've made this simple HTTP server in Python:
import SimpleHTTPServer
import SocketServer
PORT = 8000
Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
httpd = SocketServer.TCPServer(("", PORT), Handler)
print "serving at port", PORT
httpd.serve_forever()
What I want to do now, but I don't know how, is the following:
When I visit http://localhost:8000/my/path/download?documentID=100 , a document (particularly a PDF file) will start being downloaded automatically. Of course, I have more documents but I want them to be identified by the get paramater documentID
What is the easiest way to achieve this? thanks
You have to write a new handle. http://fragments.turtlemeat.com/pythonwebserver.php shows a simple example.
You have to:
determinate the PDF-File out of the ID
read the pdf file
send the right content-flag
send the pdf file
alternative:
write a script saving the pdfs with the ids like 1.pdf, 2.pdf
use your example code
and simple use links like http://localhost:8000/my/path/1.pdf
Greets Kuishi
PS: English isn't my native language, sorry
I'm new to using Cloud9 IDE (c9) and so far it looks great, except a few minor things.
I see from the docs that to start up a simple node.js http server, you have to pass in process.env.PORT in place of the regular port such as "8080".
Node Hello World example:
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(process.env.PORT, process.env.IP);
What I want to know is, on c9, can you only start services on ports using javascript / node.js? Or do other languages work just as well, perhaps with some other method of passing the port? Specifically python + Twisted?
I uploaded some twisted code that was working locally for me, but wouldn't work on c9 because it was trying to access local ports (which are already in use). Here is the error
twisted.internet.error.CannotListenError: Couldn't listen on any:8080: [Errno 98] Address already in use.
How would one make the following example work, if even possible, running on c9?
Python+Twisted Hello World example
from twisted.web import server, resource
from twisted.internet import reactor
class Simple(resource.Resource):
isLeaf = True
def render_GET(self, request):
return "<html>Hello, world!</html>"
site = server.Site(Simple())
reactor.listenTCP(8080, site)
reactor.run()
Initial searches through the documentation and github issues did not turn much up. I'm hoping this is possible and I just missed the right parameter to pass.
Edit: Updated output below
Node Code
console.log(process.env.PORT)
console.log(process.env.IP)
Terminal output
Running Node Process
Tip: you can access long running processes, like a server, at 'http://private-cloud.mrchampe.c9.io'.
Important: in your scripts, use 'process.env.PORT' as port and 'process.env.IP' as host.
8080
127.6.70.129
Python Code
import os
print os.environ["PORT"]
print os.environ["IP"]
Terminal output
Running Python Process
8080
127.6.70.129
Twisted code
import os
import twisted
from twisted.web import server, resource
from twisted.internet import reactor
class Simple(resource.Resource):
isLeaf = True
def render_GET(self, request):
return "<html>Hello, world!</html>"
site = server.Site(Simple())
reactor.listenTCP(int(os.environ["PORT"]), interface=os.environ["IP"])
reactor.run()
Terminal Output
Running Python Process
hello world
Traceback (most recent call last):
File "python/hello.py", line 17, in <module>
reactor.listenTCP(int(os.environ["PORT"]), interface=os.environ["IP"])
TypeError: listenTCP() takes at least 3 non-keyword arguments (2 given)
The listenTCP TypeError is strange because 2 arguments works locally but not on Cloud9. I don't see why using these arguments does not work.
I have the above code hosted on this public Cloud9 project for anyone to take a look. Thanks!
process.env.PORT and process.env.IP from Node.js sound like os.environ["PORT"] and os.environ["IP"] in Python. Perhaps you can try:
reactor.listenTCP(int(os.environ["PORT"]), site, interface=os.environ["IP"])
Probably this is limitation of c9 environment management, so users dont abuse their service too much. I would assume that they have some level of management for Node.js used resources and thus allow these to open ports.
If this was the case and I had to work with cloud9, I would probably approach this as follows:
- create Node.js service which would act as a proxy, listening on twisted behalf
- create new reactor with overriden listenTCP and listenUDP methods, which would bind these to Node.js proxy service.
The way how proxy would work is as follows, Node.js would initially listen on one "management" TCP port. Then, when twisted service starts up, it would create a TCP connection between Node.js and itself through that port. Then, whenever listenTCP or listenUDP is called, these commands would then be dispatched to Node.js service, which in return would open the port and all of the comunication through that port would then be proxied to twisted through that existing TCP connection.
It's worth mentioning that Jean-Paul's answer worked for me as well, but I had to use 'address' instead of 'interface':
http_server.listen(int(os.environ.get("PORT")), address=os.environ["IP"])
Because cross-domain xmlrpc requests are not possible in JavaScript
I need to create a Python app which exposes both some HTML through HTTP and an XML-RPC service on the same domain.
Creating an HTTP request handler and SimpleXMLRPCServer in python is quite easy,
but they both have to listen on a different port, which means a different domain.
Is there a way to create something that will listen on a single port on the localhost
and expose both the HTTPRequestHandler and XMLRPCRequest handler?
Right now I have two different services:
httpServer = HTTPServer(('localhost',8001), HttpHandler);
xmlRpcServer = SimpleXMLRPCServer(('localhost',8000),requestHandler=RequestHandler)
Update
I cannot install Apache on the device
The hosted page will be a single html page
The only client will be the device on witch the python service runs itself
Both of them subclass of SocketServer.TCPServer. There must be someway to refactor them so that once server instance can dispatch to both.
An easier alternative may be to keep the HTTPServer in front and proxy XML RPC to the SimpleXMLRPCServer instance.
The solution was actually quite simple, based on Wai Yip Tung's reply:
All I had to do was keep using the SimpleXMLRPCServer instance,
but modify the handler:
class RequestHandler(SimpleXMLRPCRequestHandler):
rpc_paths = ('/RPC2',)
def do_GET(self):
#implementation here
This will cause the handler to respond to GET requests as well as the original POST (XML-RPC) requests.
Using HTTPServer for providing contents is not a good idea. You should use a webserver like Apache and use Python as CGI (or a more advanced interface like mod_wsgi).
Then, the webserver is running on one port and you can server HTML directly over the webserver and write as many CGI scripts as you like in Python, as example one for XMLRPC requests using CGIXMLRPCRequestHandler.
class MyFuncs:
def div(self, x, y) : return x // y
handler = CGIXMLRPCRequestHandler()
handler.register_function(pow)
handler.register_function(lambda x,y: x+y, 'add')
handler.register_introspection_functions()
handler.register_instance(MyFuncs())
handler.handle_request()