如何使用Python实现一个简单的Web服务器而不使用任何库?

8

我需要在Python中实现一个非常简单的类似于Web服务器的应用程序,它将执行基本的HTTP请求和响应,并在网页上显示非常基本的输出。我并不太关心实际在Python中编码,但我不确定从哪里开始?如何设置这个?一个文件?多个文件?我猜我不知道如何处理这是一个“服务器”的事实 - 所以我不熟悉如何处理HTTP请求/套接字/处理请求等。有什么建议?资源?


请进一步解释您的需求(以及原因)。您是想实现完整的应用程序级堆栈,还是可以使用例如Apache?更详细地解释您需要什么以及为什么需要。最后,当您使用“websocket”标签时,您是否真正需要它,还是只是错误使用的标签? - Chris Morgan
2
不使用任何库?最起码需要“socket”吧? - Wooble
请查看此文档页面:http://docs.python.org/library/simplehttpserver.html。在这里,我假设“任何库”是指未包含在Python安装中的库。 - Emil M
@Wooble:我认为假设“任何库”指的是“任何非标准库”是相当公平的。 - Chris Morgan
4个回答

10
你应该查看SimpleHttpServer(py3:http.server)模块。
根据你想做什么,你可以直接使用它,或者查看模块的源代码(py2py3)以获取灵感。
如果你想更低级一些,SimpleHttpServer扩展了BaseHttpServersource),使其能够正常工作。
如果你想更加深入地了解,可以查看SocketServer(来源:py2py3)。
如果只是想共享一个目录,人们通常会像这样运行Python:python -m SimpleHttpServer(或python3 -m http.server):这是一个完全功能的简单服务器。

我会建议你先查看HTTP文档,例如RFC。 - zinking

6
你可以使用套接字编程来实现这个目的。以下代码片段创建了一个TCP套接字并监听9000端口上的HTTP请求:
from socket import *

def createServer():
    serversocket = socket(AF_INET, SOCK_STREAM)
    serversocket.bind(('localhost',9000))
    serversocket.listen(5)
    while(1):
        (clientsocket, address) = serversocket.accept()
        clientsocket.send("HTTP/1.1 200 OK\n"
         +"Content-Type: text/html\n"
         +"\n" # Important!
         +"<html><body>Hello World</body></html>\n")
        clientsocket.shutdown(SHUT_WR)
        clientsocket.close()

    serversocket.close()

createServer()

启动服务器,$ python server.py。 在您的Web浏览器中打开http://localhost:9000/(作为客户端)。然后在浏览器窗口中,您可以看到文本“Hello World”(HTTP响应)。

编辑** 先前的代码仅在Chrome上进行了测试,并且由于您们建议其他浏览器,因此代码已修改为:

  1. 要使响应类似于HTTP,可以使用普通标题发送HTTP版本1.1、状态码200 OK和内容类型text/html。
  2. 客户端套接字在提交响应后需要关闭,因为它是TCP套接字。
  3. 为正确关闭客户端套接字,需要调用shutdown()socket.shutdown vs socket.close

然后在Chrome、Firefox(http://localhost:9000/)和终端中的简单curl(curl http://localhost:9000)上测试了该代码。


4
你试过这个吗?它根本不起作用,它是一个套接字服务器,但不能处理HTTP请求。 - Asherah
3
它实际上并不支持HTTP协议,因此几乎所有浏览器都不能与其配合使用。在Chrome中无法运行。在Firefox中只有在按下停止按钮时才能正常工作。它不是一个网络服务器。 - Asherah
我复制了你的脚本并运行它,但是出现了一个错误,说“需要一个字节类似的对象而不是'str'”,我该如何解决? - Xantium
3
@Simon 修改了一下代码。此外,它在 Python 2.7.6 上进行了测试。如果您正在使用 Python 3,那么字符串是Unicode;但在网络传输时,我们需要发送字节串而不是字符串。因此,请尝试将字符串输出编码为 utf-8 并使用 sendall() 替代 send()。 #START output = "It works" clientsocket.sendall(output.encode("utf-8")) #END - pritam
太好了!这正是我需要的。我使用Python 3,因此 sendall().encode("utf-8") 绝对必不可少,这两个函数都解决了我遇到的错误。到目前为止,我的所有服务器尝试都失败了,所以我非常感激。这是一个应该受到赞赏的回答,但我不喜欢 clientsocket.send("HTTP/1.1 200 OK\n" +"Content-Type: text/html\n" +"\n" # Important! +"<html><body>Hello World</body></html>\n")。难道那不应该在同一行上吗?我不得不修改那一部分。再次感谢。:) - Xantium
显示剩余2条评论

2

我决定使用Python 3来制作这个项目,并且让它可以在Chrome中使用,以便作为我正在开发的在线课程的示例。当然,Python 3需要在正确的位置使用encode()decode()。而Chrome则希望在获取数据之前发送GET请求。我还添加了一些错误检查,以确保在中止服务器或出现故障时清理其套接字:

def createServer():
    serversocket = socket(AF_INET, SOCK_STREAM)
    try :
        serversocket.bind(('localhost',9000))
        serversocket.listen(5)
        while(1):
            (clientsocket, address) = serversocket.accept()

            rd = clientsocket.recv(5000).decode()
            pieces = rd.split("\n")
            if ( len(pieces) > 0 ) : print(pieces[0])

            data = "HTTP/1.1 200 OK\r\n"
            data += "Content-Type: text/html; charset=utf-8\r\n"
            data += "\r\n"
            data += "<html><body>Hello World</body></html>\r\n\r\n"
            clientsocket.sendall(data.encode())
            clientsocket.shutdown(SHUT_WR)

    except KeyboardInterrupt :
        print("\nShutting down...\n");
    except Exception as exc :
        print("Error:\n");
        print(exc)

    serversocket.close()

print('Access http://localhost:9000')
createServer()

服务器还会打印出收到的HTTP请求。无论浏览器请求什么,代码都只会发送text/html - 即使浏览器请求favicon。
$ python3 server.py
Access http://localhost:9000
GET / HTTP/1.1
GET /favicon.ico HTTP/1.1
^C
Shutting down...

但这是一个很好的例子,大多数情况下它展示了为什么你想使用像Flask或DJango这样的框架而不是编写自己的框架。感谢提供初始代码。


-1

上面提到了一个非常简单的解决方案,但是上面的解决方案并不起作用。这个解决方案在Chrome上经过测试,可以正常工作。这是Python 3,尽管我从未在Python 2上测试过。

from socket import *

def createServer():
    serversocket = socket(AF_INET, SOCK_STREAM)
    serversocket.bind(('localhost',9000))
    serversocket.listen(5)
    while(1):
        (clientsocket, address) = serversocket.accept()
        clientsocket.send(bytes("HTTP/1.1 200 OK\n"
         +"Content-Type: text/html\n"
         +"\n" # Important!
         +"<html><body>Hello World</body></html>\n",'utf-8'))
        clientsocket.shutdown(SHUT_WR)
        clientsocket.close()

    serversocket.close()

createServer()

这是对已被接受的答案进行改进,但我会发布它,以便未来的用户可以轻松使用它。


欢迎来到 Stack Overflow。这个问题与 @drchuck 提供的答案几乎相同(https://dev59.com/NGLVa4cB1Zd3GeqPxIem#53157058)。唯一的区别是缺少异常处理。 - chb

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