21.12 Python 实现网站服务器

Web服务器本质上是一个提供Web服务的应用程序,运行在服务器上,用于处理HTTP请求和响应。它接收来自客户端(通常是浏览器)的HTTP请求,根据请求的URL、参数等信息生成HTTP响应,并将响应返回给客户端,完成客户端的请求。Web服务器可以使用多种编程语言和技术实现,通过对套接字的处理并遵循HTML等浏览器兼容格式即可实现。

如果需要自行实现一个Web服务器则本质上就是需要完成套接字的处理,并在处理时增加遵循HTTP格式的头部数据即可,如下是一个简单的支持Web服务器的套接字程序,该程序运行后会在本机的80端口侦听,当用于通过浏览器访问时则会自动传输一段话。

import socket

def handle_request(client):
buf = client.recv(1024)
client.send(bytes("HTTP/1.1 200 OK\r\n\r\n","UTF-8"))
client.send(bytes("<b>Hello lyshark</b>","UTF-8"))

if __name__ == "__main__":
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(("localhost",80))
sock.listen(5)

while True:
connection, address = sock.accept()
handle_request(connection)
connection.close()

运行上述代码片段,读者可自行打开浏览器并访问http://localhost:80端口,则此时会弹出一段问候语,说明我们的服务器已经可以被浏览器解析了。

当然上述代码还有很大的优化空间,首先要解决的问题是让页面具有动态渲染的功能,此处我们可以采用jinja2模板,该模板允许在Web应用程序中渲染HTML,其主要特点是可配置性高、快速、安全且易于使用,使用时读者需要自行执行pip install jinja2来安装此模板,至此我们就可以在Web服务器带啊吗中使用模板引擎进行输出。

如下代码片段则是一个使用了make_server类的服务器实现,在代码中我们定义了一个url_func列表用于存储路由规则,路由规则代表的是当有浏览器访问服务器时则自动使用特定规则内的特定函数处理这个规则,在代码中我们分别定义了两个路由函数,其中index()用于展示首页信息,而jinja()则用于展示模板渲染功能实现,至此读者需要在主目录下分别创建两个文件index.html代表网站主页,而jinja.html则代表模板渲染页面,我们以jinja.html为例创建如下代码;

<body>
<h1>{{name}}</h1>
<ul>
{% for item in user_list %}
<li>{{item}}</li>
{% endfor %}
</ul>
</body>

接着编写服务器程序,在jinja()路由函数内通过读取jinja.html文件并使用template.render()函数给特定的变量传入不同的参数,当页面渲染好以后,则通过return将该请求返回给RunServer函数,再由该函数return [response,]返回给被调用客户。

from wsgiref.simple_server import make_server
from jinja2 import Template

# /index/的路由函数
def index():
with open("./index.html","r",encoding="utf-8")as fp:
recv = fp.read()
return recv.encode("utf-8")

# /jinja/的路由函数
def jinja():
with open("./jinja.html","r",encoding="utf-8")as fp:
data = fp.read()
template = Template(data)
recv = template.render(name='John Doe', user_list=['lyshark', 'wang'])
return recv.encode("utf-8")

# 定义路由规则
url_func = [
('/index/',index),('/jinja/',jinja)]

def RunServer(environ,star_response):
star_response("200 OK",[('Content-Type','text/html;charset=urf-8')])
url = environ["PATH_INFO"]
rAddr = environ["REMOTE_ADDR"]
rHost = environ["HTTP_HOST"]
print("[+] 根域名: {} 路径: {} 目标IP: {}".format(rHost,url,rAddr))
func = None
for i in url_func:
if i[0] == url:
func = i[1]
break
if func:
response = func()
else:
response = b"** 404 not found **"
return [response,]

if __name__ == "__main__":
httpd = make_server("0.0.0.0",80,RunServer)
print("[*] 服务已启动 0.0.0.0:80")
httpd.serve_forever()

运行上述代码,读者可以打开浏览器并访问localhost/jinja/路径,此时即可看到经过选然后的HTML页面,如下图所示;