如何运行一个HTTP服务器来提供特定路径的服务?

125

这是我的Python3项目层次结构:

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

但这实际上是为项目服务的,而不是网页。我该如何指定我想要提供服务的文件夹路径?

但是这实际上是为项目提供服务的,而不是网页。我怎样才能指定要提供服务的文件夹路径呢?


11
你考虑过在命令行上运行 python3 -m http.server -d /path/to/web/dir 来完成任务吗?感谢@kyle-barron在评论中提供了这个完美的解决方案。 - Akseli Palén
我建议这是最佳答案:https://dev59.com/cVkS5IYBdhLWcg3wemv6#58217918 - Konrad Kleine
@AkseliPalén 当我在Ubuntu 18.04终端(使用python3.6.9)运行时,我会得到server.py: error: argument port: invalid int value: '/media/EHD/web_root'错误。 - Lost Crotchet
8个回答

105
在Python 3.7中,SimpleHTTPRequestHandler 支持使用 directory 参数。
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()

并且从命令行进行:

python -m http.server --directory web

要有些疯狂的想法...你可以为任意目录创建处理程序:


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

最好使用http.server.HTTPServer(与socketserver.TCPServer完全相同的方式)。 - Andrew
类似:https://dev59.com/Nl0a5IYBdhLWcg3wRW6V#30516693 - Andrew

82

如果你只想提供静态文件,可以使用Python 2运行SimpleHTTPServer模块来实现:

 python -m SimpleHTTPServer

或者使用 Python 3:

 python3 -m http.server

这样,您就不需要编写任何脚本。


3
注意,您还可以在末尾添加一个端口来指定服务器的端口。 - rbaleksandar
1
进一步说明:您必须在运行服务器的目录中拥有一个 index.htmlindex.htm 文件,以便它能够被提供;否则您将得到一个目录列表。 - cori
3
OP问如何在特定的文件夹路径下运行它,而不是从当前工作目录运行。 - Nikhil VJ
57
http.server 命令有一个目录参数,因此你可以使用 python3 -m http.server -d /path/to/web/dir 命令来指定网页的路径。 - Kyle Barron
3
虽然这个答案被问题的所有者接受为最佳答案,但我认为它不应该是最佳答案。问题是在询问如何在Python中编写代码,而不是如何从命令行调用它。 - Konrad Kleine
显示剩余2条评论

52

https://docs.python.org/zh-cn/3/library/http.server.html#http.server.SimpleHTTPRequestHandler

这个类可以从当前目录及其下面的目录中提供文件,并将目录结构直接映射到HTTP请求。

所以在启动服务器之前,您只需要更改当前目录-请参见os.chdir

例如:

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

4
谢谢!注意:我添加了try语句:httpd.serve_forever(); except KeyboardInterrupt: pass; httpd.server_close()以确保关闭端口。 - roipoussiere
谢谢。它起作用了。但是我怎么才能得到主机地址呢?我的意思是说,我怎么才能得到0.0.0.0:8000而不是我的本地路由器地址192.168.0.100:8000? - Istiyak
@roipoussiere 你最好采用 with socketserver.TCPServer(("", PORT), Handler) as httpd: 这种方式,这样它在使用后会自动关闭。 - Daniel
2
对于未来的读者:Andy Hayden下面的解决方案不太“hacky”,可能更受欢迎,因为它不依赖于副作用。 - Vinícius M

29

你也可以使用命令行来运行

python3 -m http.server -d web 8000

2
返回已翻译的文本:或者尝试输入 python3 -m http.server --help 查看所有支持的参数。 - ccpizza

26

对于Python 3+,有一种更短的方法:

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

1
这是一种非常酷的方法,对我很有效。我绝对推荐这个作为最佳答案! - Konrad Kleine
TypeError: __init__() got an unexpected keyword argument 'directory' - e-info128
我在Python 2.7中遇到了相同的错误。在Python 3.8上它对我起作用。 - Dan
19
停止使用Python 2 :) - Habbie

21

为了完整起见,以下是您可以设置实际服务器类来从任意目录提供文件的方式:

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)

然后你可以在你的代码中设置任意路径:

web_dir = os.path.join(os.path.dirname(__file__), 'web')
httpd = HTTPServer(web_dir, ("", 8000))
httpd.serve_forever()

8

另一种从特定目录提供服务的简单方法。

因为您只需要为SimpleHTTPRequestHandler设置directory参数,所以可以使用functools.partial准备处理程序类而不实例化该类。

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

-8

如果你只需要一个现代的Web 静态服务器
deno是一个没有任何代码的替代文件服务器

一行命令安装deno

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

使用单行命令安装文件服务器

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

使用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>/

阅读更多https://deno.land/manual/examples/file_server#using-the-codestdhttpcode-file-server


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接