• Python Web 框架原理


    Web Socket

    所谓 Web 服务,本质上就是用户使用一个 socket 客户端(浏览器)去访问一个 socket 服务端。

    下面是一个最基础的基于 socket 的 Python Web 服务端程序。

    import socket
    
    
    # 最简单的web程序
    def handle_request(connection):
    	content = connection.recv(1024)
    	print(content)
    	connection.send(bytes("HTTP/1.1 200 OK
    
    ".encode("utf-8")))
    	connection.send(bytes("hello, World!".encode("utf-8")))
    
    
    def service():
    	server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    	server_address = ('127.0.0.1', 8000)
    	server.bind(server_address)
    	server.listen(5)
    
    	while True:
    		connection, client_address = server.accept()
    		print(connection)
    		handle_request(connection)
    		connection.close()
    
    
    if __name__ == '__main__':
    	service()
    

    浏览器发起请求

    服务端接收请求

    WSGI (Web Server Gateway Interface)

    上面的例子展示了 Web 的本质。

    但是对于现实中的 Python Web 程序来说,一般服务端程序会分为两部分:

    • 服务器程序(用来接收、整理客户端发送的请求)
    • 应用程序(处理服务器程序传递过来的请求)

    而在服务端开发应用程序时,我们会把常用的功能函数封装起来,这就是各种 Web 框架了。

    Python 常见的 Web 框架有 Django,Flask,Tornado 等等。

    不同的框架提供了不同程度和方式的封装,方便程序员在其上进行二次开发。

    但是,服务器程序应用程序 需要相互配合才能给用户提供服务,因此我们需要制定一个标准,只要双方同时遵守这个标准,就可以相互配合了。

    在 Python 中,这个标准就是 WSGI 了。

    WSGI 是一种规范,它规定了服务器程序和应用程序各自使用的接口和功能,实现了二者的解耦。

    Python 标准库提供的独立 WSGI 服务器称之为 wsgiref

    from wsgiref.simple_server import make_server
    
    
    def application(environ, start_response):
    	start_response('200 OK', [('Content-Type', 'text/html')])
    	return [bytes('<h1>Hello, World</h1>'.encode("utf-8")), b'42']
    
    
    def run_server():
    	server = make_server("127.0.0.1", 8000, application)
    	server.serve_forever()
    
    
    if __name__ == '__main__':
    	run_server()
    

    路径处理

    上面的例子虽然实现了一个正常的服务端功能,但却有一个巨大的缺陷,那就是不同的 url 也只能返回相同的内容,为了解决这个问题,我们对代码作出如下修改。

    from wsgiref.simple_server import make_server
    
    
    def application(environ, start_response):
        url = environ['PATH_INFO']
        print("url:", url)
        start_response('200 OK', [('Content-Type', 'text/html')])
        if url == "/index":
            return [bytes('<h1>index!</h1>'.encode("utf-8")), b'42']
        elif url == "/login":
            return [bytes('<h1>login !</h1>'.encode("utf-8")), b'42']
        elif url == "/logout":
            return [bytes('<h1>logout !</h1>'.encode("utf-8")), b'42']
        else:
            return [bytes('<h1>404 !</h1>'.encode("utf-8")), b'42']
    
    
    def run_server():
        server = make_server("127.0.0.1", 8000, application)
        server.serve_forever()
    
    
    if __name__ == '__main__':
        run_server()
    

    通过从 environ 中获取存储着路径的变量 PATH_INFO。我们就可以对不同的 url 返回不同的结果了。

    分层处理

    上面的例子虽然做到了对不同的路径返回不同的结果,但是所有的逻辑都写在一个函数内,一旦体量增加就会混乱不堪。

    因此我们需要对应用程序进行进一步的解耦。

    from wsgiref.simple_server import make_server
    
    
    def index():
    	return [bytes('<h1>index!</h1>'.encode("utf-8")), b'42']
    
    
    def login():
    	return [bytes('<h1>login !</h1>'.encode("utf-8")), b'42']
    
    
    def logout():
    	return [bytes('<h1>logout !</h1>'.encode("utf-8")), b'42']
    
    
    urlConf = [
    	("/index", index),
    	("/login", login),
    	("/logout", logout),
    ]
    
    # 不同的网址有不同的结果,但是所有的处理逻辑写到一起,很混乱
    def application(environ, start_response):
    	url = environ['PATH_INFO']
    	print("url:", url)
    
    	response_fun = None
    
    	for item in urlConf:
    		if url == item[0]:
    			response_fun = item[1]
    			break
    
    	if response_fun:
    		start_response('200 OK', [('Content-Type', 'text/html')])
    		response_body = response_fun()
    	else:
    		start_response('404 Not Found', [('Content-Type', 'text/html')])
    		response_body = [bytes('<h1>404 !</h1>'.encode("utf-8")), b'42']
    	return response_body
    
    
    def run_server():
    	server = make_server("127.0.0.1", 8000, application)
    	server.serve_forever()
    
    
    if __name__ == '__main__':
    	run_server()
    
    

    

    怎么样是不是已经有点像我们平时使用的各种框架了。

    urlConf用户根据不同的路径,配置不同的函数。

    server程序中遍历urlConf来根据路径定位所要执行的函数。

    文件拆分

    上面的例子已经有了框架的雏形了,但所有的功能都在一个 Python 文件中,很不优雅。

    这时你就可以将代码分成三个文件。

    view.py:专门用户存放各种页面的处理函数

    url.py 配置路径和函数的关系

    server.py 执行web的主程序

    将不同功能的代码分门别类存放,进行进一步的解耦。

  • 相关阅读:
    天明闹钟开发过程3
    降低 TCP ACK 延迟造成的网络性能损失
    TCP SYN,ACK 详解
    TCP的SEQ和ACK的生成
    python之线程(threading)
    python之进程(multiprocess)
    python之发送邮件~
    python之函数参数问题(参数为可变对象)
    python之斐波那契数列递归推导在性能方面的反思
    linux中一些简便的命令之tac/comm
  • 原文地址:https://www.cnblogs.com/leisurelylicht/p/Python-Web-kuang-jia-yuan-li.html
Copyright © 2020-2023  润新知