如何运行提供特定路径的 http 服务器?

这是我的 Python 3项目结构:

projet
\
script.py
web
\
index.html

script.py,我想运行一个 http 服务器,其中服务的内容的 web文件夹。

这里 建议这段代码运行一个简单的 http 服务器:

import http.server
import socketserver


PORT = 8000
Handler = http.server.SimpleHTTPRequestHandler
httpd = socketserver.TCPServer(("", PORT), Handler)
print("serving at port", PORT)
httpd.serve_forever()

但这实际上服务于 project,而不是 web。我如何指定我要服务的文件夹的路径?

124209 次浏览

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 ABC0 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()

There's a shorter method for Python 3+:

import functools
    

Handler = functools.partial(http.server.SimpleHTTPRequestHandler, directory='/my/dir/goes/here')

You also can run the command line with

python3 -m http.server -d web 8000

Another easy method to serve from a specific directory.

Since you really only need to set the directory parameter for the SimpleHTTPRequestHandler, you can use functools.partial to prepare the handler class without instantiating the class.

from functools import partial
from http.server import HTTPServer, SimpleHTTPRequestHandler
from pathlib import Path




def start_httpd(directory: Path, port: int = 8000):
print(f"serving from {directory}...")
handler = partial(SimpleHTTPRequestHandler, directory=directory)
httpd = HTTPServer(('localhost', port), handler)
httpd.serve_forever()
    

If you just need a modern web static server,
deno is an alternative file server without any code.

install deno with single line

https://github.com/denoland/deno_install#deno_install

install file server with single line

deno install --allow-net --allow-read https://deno.land/std@0.125.0/http/file_server.ts

use deno file-server

file_server . --port=<port>
# Downloading https://deno.land/std@0.125.0/http/file_server.ts...
# HTTP server listening on http://0.0.0.0:<port>/

read more https://deno.land/manual/examples/file_server#using-the-codestdhttpcode-file-server