zoukankan      html  css  js  c++  java
  • 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的主程序

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

  • 相关阅读:
    每日日报2020.12.1
    每日日报2020.11.30
    981. Time Based Key-Value Store
    1146. Snapshot Array
    565. Array Nesting
    79. Word Search
    43. Multiply Strings
    Largest value of the expression
    1014. Best Sightseeing Pair
    562. Longest Line of Consecutive One in Matrix
  • 原文地址:https://www.cnblogs.com/leisurelylicht/p/Python-Web-kuang-jia-yuan-li.html
Copyright © 2011-2022 走看看