this is my Python3 project hiearchy:
projet
\
script.py
web
\
index.html
From script.py
, I would like to run a http server which serve the content of the web
folder.
Here is suggested this code to run a simple http server:
import http.server
import socketserver
PORT = 8000
Handler = http.server.SimpleHTTPRequestHandler
httpd = socketserver.TCPServer(("", PORT), Handler)
print("serving at port", PORT)
httpd.serve_forever()
but this actually serve project
, not web
. How can I specify the path of the folder I want to serve?
https://docs.python.org/3/library/http.server.html#http.server.SimpleHTTPRequestHandler
This class serves files from the current directory and below, directly
mapping the directory structure to HTTP requests.
So you just need to change the current directory prior to starting the server - see os.chdir
eg:
import http.server
import socketserver
import os
PORT = 8000
web_dir = os.path.join(os.path.dirname(__file__), 'web')
os.chdir(web_dir)
Handler = http.server.SimpleHTTPRequestHandler
httpd = socketserver.TCPServer(("", PORT), Handler)
print("serving at port", PORT)
httpd.serve_forever()
If you just want serve static file you can do it by running SimpleHTTPServer module using python 2:
python -m SimpleHTTPServer
Or with python 3:
python3 -m http.server
This way you do not need to write any script.
Just for completeness, here's how you can setup the actual server classes to serve files from an arbitrary directory:
try
# python 2
from SimpleHTTPServer import SimpleHTTPRequestHandler
from BaseHTTPServer import HTTPServer as BaseHTTPServer
except ImportError:
# python 3
from http.server import HTTPServer as BaseHTTPServer, SimpleHTTPRequestHandler
class HTTPHandler(SimpleHTTPRequestHandler):
"""This handler uses server.base_path instead of always using os.getcwd()"""
def translate_path(self, path):
path = SimpleHTTPRequestHandler.translate_path(self, path)
relpath = os.path.relpath(path, os.getcwd())
fullpath = os.path.join(self.server.base_path, relpath)
return fullpath
class HTTPServer(BaseHTTPServer):
"""The main server, you pass in base_path which is the path you want to serve requests from"""
def __init__(self, base_path, server_address, RequestHandlerClass=HTTPHandler):
self.base_path = base_path
BaseHTTPServer.__init__(self, server_address, RequestHandlerClass)
Then you can set any arbitrary path in your code:
web_dir = os.path.join(os.path.dirname(__file__), 'web')
httpd = HTTPServer(web_dir, ("", 8000))
httpd.serve_forever()
In Python 3.7 SimpleHTTPRequestHandler
can take a directory
argument:
import http.server
import socketserver
PORT = 8000
DIRECTORY = "web"
class Handler(http.server.SimpleHTTPRequestHandler):
def __init__(self, *args, **kwargs):
super().__init__(*args, directory=DIRECTORY, **kwargs)
with socketserver.TCPServer(("", PORT), Handler) as httpd:
print("serving at port", PORT)
httpd.serve_forever()
and from the command line:
python -m http.server --directory web
To get a little crazy... you could make handlers for arbitrary directories:
def handler_from(directory):
def _init(self, *args, **kwargs):
return http.server.SimpleHTTPRequestHandler.__init__(self, *args, directory=self.directory, **kwargs)
return type(f'HandlerFrom<{directory}>',
(http.server.SimpleHTTPRequestHandler,),
{'__init__': _init, 'directory': directory})
with socketserver.TCPServer(("", PORT), handler_from("web")) as httpd:
print("serving at port", PORT)
httpd.serve_forever()