无法 运行 Docker 中的 BaseHTTPServer

Unable to run BaseHTTPServer in Docker

我有以下 python 代码,其中我通过扩展 HTTPBaseServer 编写了一个简单的 HTTP 服务器:

class ApiError(Exception):
    def __init__(self, code, msg=None, desc=None):
        self.code = code
        self.msg = msg
        self.desc = desc

    def __str__(self):
        return f"ApiError({self.code}, {self.msg})"


def ApiRoute(path):
    def outer(func):
        if not hasattr(func, "_routes"):
            setattr(func, "_routes", [])
        func._routes += [path]
        return func
    return outer


class ApiServer(HTTPServer):
    def __init__(self, addr, port):
        server_address = (addr, port)
        self.__addr = addr

        class handler_class(ApiHandler):
            pass

        self.handler_class = handler_class

        # routed methods map into handler
        for meth in type(self).__dict__.values():
            if hasattr(meth, "_routes"):
                for route in meth._routes:
                    self.add_route(route, meth)

        super().__init__(server_address, handler_class)

    def add_route(self, path, meth):
        self.handler_class._routes[path] = meth

    def port(self):
        "Get my port"
        sa = self.socket.getsockname()
        return sa[1]

    def address(self):
        "Get my ip address"
        sa = self.socket.getsockname()
        return sa[0]

    def uri(self, path):
        "Make a URI pointing at myself"
        if path[0] == "/":
            path = path[1:]
        return "http://"+self.__addr + ":"+ str(self.port()) + "/" + path

    def shutdown(self):
        super().shutdown()
        self.socket.close()


class ApiHandler(BaseHTTPRequestHandler):
    _routes={}

    def do_GET(self):
        self.do_XXX()

    def do_XXX(self, info={}):
        url=urlparse.urlparse(self.path)

        handler = self._routes.get(url.path)

        if handler:
            response=handler(info)
            self.send_response(200)
            response = json.dumps(response)
            response = bytes(str(response),"utf-8")
            self.send_header("Content-Length", len(response))
            self.end_headers()
            self.wfile.write(response)


class MyServer(ApiServer):
    @ApiRoute("/popup")
    def popup(req):
        return "HERE"


httpd = MyServer('127.0.0.1', 5000)
print("serving on ", httpd.address(), httpd.port())
threading.Thread(target=httpd.serve_forever).start()

当我这样做时,上面的方法非常有效,

python serv.py

在终端上。

但是,我想 运行 在 docker 容器中。 Docker文件如下所示:

FROM python:3.6-alpine3.7

COPY . /serv

WORKDIR /serv

ENTRYPOINT ["python"]
CMD ["serv.py"]

然后我构建 Docker 图像使用:

docker build . -t custom-serv

并且运行它作为容器使用:

docker run --rm -p 5000:5000 custom-serv

我收到指示服务器成功启动的日志消息,但是 url returns 上的 curl 如下:

curl: (56) Recv failure: Connection reset by peer

我意识到,有很多框架可以让生活变得更简单,但是这更像是我正在做的一个实验,如果有人能给我指明正确的方向,那就太好了!

更改该行:

httpd = MyServer('127.0.0.1', 5000)

至:

httpd = MyServer('0.0.0.0', 5000)

关于差异:https://www.howtogeek.com/225487/what-is-the-difference-between-127.0.0.1-and-0.0.0.0/

您的服务器在本地主机上侦听并且不响应任何其他连接,而是来自本地主机。如果您要从 容器中连接到您的服务器,它就可以工作。但是要从外部连接,您需要指定您的服务器从所有个可用位置侦听所有个连接。

因此,您需要更改

httpd = MyServer('127.0.0.1', 5000)

httpd = MyServer('0.0.0.0', 5000)