【问题标题】:How to run a http server which serves a specific path?如何运行服务于特定路径的 http 服务器?
【发布时间】:2017-02-09 15:12:50
【问题描述】:

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

projet
  \
  script.py
  web
    \
    index.html

来自script.py,我想运行一个http 服务器来提供web 文件夹的内容。

Here 建议使用此代码来运行一个简单的 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。如何指定要服务的文件夹的路径?

【问题讨论】:

  • 您是否考虑过在命令行上运行python3 -m http.server -d /path/to/web/dir 来完成这项工作?支持@kyle-barron,他在下面的a comment 中提供了这个完美的解决方案。
  • 我建议这是最好的答案:stackoverflow.com/a/58217918/835098
  • @AkseliPalén 我在 Ubuntu 18.04 终端(使用 python3.6.9)中运行时收到 server.py: error: argument port: invalid int value: '/media/EHD/web_root' 错误

标签: python python-3.x simplehttpserver


【解决方案1】:

https://docs.python.org/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()

【讨论】:

  • 谢谢!注意:我添加了 try:httpd.serve_forever(); except KeyboardInterrupt: pass; httpd.server_close() 来实际关闭端口。
  • 谢谢。它的工作。但是我怎样才能得到主机地址呢?我的意思是说我怎样才能得到 0.0.0.0:8000 而不是我的本地路由器地址 192.168.0.100:8000
  • @roipoussiere 你宁愿使用with socketserver.TCPServer(("", PORT), Handler) as httpd:,这样使用后会自动关闭
  • 对于未来的读者:下面安迪·海登的解决方案不那么“hacky”,可能是首选,因为它不依赖于副作用。
【解决方案2】:

如果您只想提供静态文件,您可以使用 python 2 运行 SimpleHTTPServer 模块:

 python -m SimpleHTTPServer

或者使用 python 3:

 python3 -m http.server

这样你就不需要编写任何脚本了。

【讨论】:

  • 注意,也可以在末尾加一个端口来指定服务器的端口。
  • 进一步说明;您必须在运行服务器的目录中有一个index.htmlindex.htm 文件,才能为其提供服务;否则你会得到一个目录列表。
  • OP 询问如何在特定文件夹路径下运行它,而不是从当前工作目录运行。
  • http.server 有一个目录参数。所以你可以做python3 -m http.server -d /path/to/web/dir
  • 虽然这个答案被问题的所有者接受为最佳答案,但我认为它不应该是最佳答案。问题是询问如何在 python 中编写代码,而不是如何从命令行调用它。
【解决方案3】:

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

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

【讨论】:

    【解决方案4】:

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

    从命令行:

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

    【讨论】:

      【解决方案5】:

      Python 3+ 有一个更短的方法:

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

      【讨论】:

      • 这是一种非常酷的方法,它对我有用。我绝对会推荐这个作为最佳答案!
      • TypeError: __init__() got an unexpected keyword argument 'directory'
      • 我在 Python 2.7 中遇到了同样的错误。它在 Python 3.8 上对我有用。
      • 停止使用 Python 2 :)
      【解决方案6】:

      您也可以使用命令行运行

      python3 -m http.server -d web 8000
      

      【讨论】:

        【解决方案7】:

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

        由于您确实只需要为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()
            
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-08-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-01-30
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多