二、Web框架实现
作者:@skyflask
转载本文请注明出处:https://www.cnblogs.com/skyflask/p/9292101.html
目录
一、简单web(socket)
二、Web框架实现(Wsgiref)
一、简单web(socket)
在前一篇WEB框架概述一文中已经详细了解了:从浏览器键入一个URL到返回HTML内容的整个过程。说到底,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端。
最简单的Hello World程序如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import socket HOST = '' PORT = 80 listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) listen_socket.bind((HOST, PORT)) listen_socket.listen( 1 ) connection, address = listen_socket.accept() request = connection.recv( 1024 ) connection.sendall(b """HTTP/1.1 200 OK Content-type: text/html <html> <body> <h1>Hello, World!</h1> </body> </html>""" ) connection.close() |
这个代码接收简单的连接和一个客户端单一的请求,不管请求的 URL 是什么,它都会响应 HTTP 200(所以,这并不是一个真正意义上的 web 服务器)。Content-type:text/html
行代码的是 header 字段,header 用来提供请求或者响应的元信息。
我们从浏览器请求,可以得到如下结果:
这就是最简单的WEB应用。
如果要动态生成HTML,就需要把上述步骤自己来实现,每次定义发送和接受的内容。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,如果我们自己来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。正确的做法是底层代码由专门的服务器软件实现,我们用Python专注于生成HTML文档。因为我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口,让我们专心用Python编写Web业务。这个接口就是前面介绍过的WSGI:Web Server Gateway Interface。WSGI就是一种协议,描述web server(uwsgi)
如何与web application(app)
通信的规范。server
和application
的规范在PEP 3333中有具体描述。要实现WSGI协议,必须同时实现web server和web application,当前运行在WSGI
协议之上的web
框架有Bottle
, Flask
, Django
。
当然,在python中,我们可以通过WSGIref来演示一个WEB框架的实现过程。
二、Web框架实现(Wsgiref)
Wsgiref库我们在前面已经有详细认识,所以这里不再介绍。
通过Wsgiref实现一个简单的WEB sever如下:
1 2 3 4 5 6 7 8 9 10 | from wsgiref.simple_server import make_server #1、符合WSGI规范的application def application(environ, start_response): start_response( '200 OK' , [( 'Content-Type' , 'text/html' )]) return [b '<h1>Hello, world!</h1>' ] #2、Wsgiref定义启动server httpd = make_server('', 80 , application) print ( 'Serving HTTP on port 80...' ) #3、开始监听HTTP请求: httpd.serve_forever() |
用户访问结果如下:
我们从Wsgiref一文中了解到,environ其实是收集了一些环境变量(包括服务端的环境变量、客户端的请求信息以及wsgi信息),我们可以将其打印出来,添加代码:
for k,v in environ.items():
print k,v
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | TMP C:\Users\admin\AppData\Local\Temp PYTHONIOENCODING UTF - 8 COMPUTERNAME ADMIN - PC wsgi.multiprocess False _OLD_VIRTUAL_PATH C:\ProgramData\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1. 0 \;D:\install soft\python2. 7 USERDOMAIN admin - PC SERVER_PROTOCOL HTTP / 1.1 SERVER_SOFTWARE WSGIServer / 0.1 Python / 2.7 . 15 PSMODULEPATH C:\Windows\system32\WindowsPowerShell\v1. 0 \Modules\ SCRIPT_NAME COMMONPROGRAMFILES C:\Program Files\Common Files PROCESSOR_IDENTIFIER Intel64 Family 6 Model 58 Stepping 9 , GenuineIntel REQUEST_METHOD GET PROGRAMFILES C:\Program Files PROCESSOR_REVISION 3a09 PATH C:\ProgramData\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1. 0 \;D:\install soft\python2. 7 ;D:\xuequn\venv\Scripts QUERY_STRING SYSTEMROOT C:\Windows PYTHONUNBUFFERED 1 PROGRAMFILES(X86) C:\Program Files (x86) WINDOWS_TRACING_FLAGS 3 CONTENT_LENGTH HTTP_UPGRADE_INSECURE_REQUESTS 1 VIRTUAL_ENV D:\xuequn\venv HTTP_CACHE_CONTROL max - age = 0 HTTP_CONNECTION keep - alive TEMP C:\Users\admin\AppData\Local\Temp REMOTE_ADDR 127.0 . 0.1 COMMONPROGRAMFILES(X86) C:\Program Files (x86)\Common Files PROCESSOR_ARCHITECTURE AMD64 wsgi.url_scheme http ALLUSERSPROFILE C:\ProgramData SERVER_PORT 80 LOCALAPPDATA C:\Users\admin\AppData\Local HOMEPATH \Users\admin PYCHARM_MATPLOTLIB_PORT 50538 PROGRAMW6432 C:\Program Files USERNAME admin HTTP_ACCEPT text / html,application / xhtml + xml,application / xml;q = 0.9 ,image / webp,image / apng, * / * ;q = 0.8 LOGONSERVER \\ADMIN - PC PROMPT (venv) $P$G COMSPEC C:\Windows\system32\cmd.exe PROGRAMDATA C:\ProgramData PYTHONPATH D:\install soft\pycharm\PyCharm 2018.1 . 4 \helpers\pycharm_matplotlib_backend;D:\xuequn wsgi.multithread True wsgi. input <socket._fileobject object at 0x0000000002900B10 > HTTP_USER_AGENT Mozilla / 5.0 (Windows NT 6.1 ; WOW64) AppleWebKit / 537.36 (KHTML, like Gecko) Chrome / 63.0 . 3239.84 Safari / 537.36 HTTP_HOST localhost SESSIONNAME Console PATHEXT .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC PATH_INFO / FP_NO_HOST_CHECK NO WINDIR C:\Windows wsgi.file_wrapper wsgiref.util.FileWrapper HTTP_ACCEPT_ENCODING gzip, deflate, br wsgi.version ( 1 , 0 ) APPDATA C:\Users\admin\AppData\Roaming HOMEDRIVE C: SERVER_NAME admin - PC wsgi.run_once False REMOTE_HOST admin - PC SYSTEMDRIVE C: GATEWAY_INTERFACE CGI / 1.1 HTTP_ACCEPT_LANGUAGE zh - CN,zh;q = 0.9 ,en;q = 0.8 PYCHARM_HOSTED 1 NUMBER_OF_PROCESSORS 4 _OLD_VIRTUAL_PROMPT $P$G PROCESSOR_LEVEL 6 CONTENT_TYPE text / plain wsgi.errors < open file '<stderr>' , mode 'w' at 0x0000000001D62150 > COMMONPROGRAMW6432 C:\Program Files\Common Files OS Windows_NT PUBLIC C:\Users\Public USERPROFILE C:\Users\admin TMP C:\Users\admin\AppData\Local\Temp PYTHONIOENCODING UTF - 8 COMPUTERNAME ADMIN - PC wsgi.multiprocess False _OLD_VIRTUAL_PATH C:\ProgramData\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1. 0 \;D:\install soft\python2. 7 HTTP_REFERER http: / / localhost / USERDOMAIN admin - PC SERVER_PROTOCOL HTTP / 1.1 SERVER_SOFTWARE WSGIServer / 0.1 Python / 2.7 . 15 PSMODULEPATH C:\Windows\system32\WindowsPowerShell\v1. 0 \Modules\ SCRIPT_NAME COMMONPROGRAMFILES C:\Program Files\Common Files PROCESSOR_IDENTIFIER Intel64 Family 6 Model 58 Stepping 9 , GenuineIntel REQUEST_METHOD GET PROGRAMFILES C:\Program Files PROCESSOR_REVISION 3a09 PATH C:\ProgramData\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1. 0 \;D:\install soft\python2. 7 ;D:\xuequn\venv\Scripts QUERY_STRING SYSTEMROOT C:\Windows PYTHONUNBUFFERED 1 PROGRAMFILES(X86) C:\Program Files (x86) WINDOWS_TRACING_FLAGS 3 CONTENT_LENGTH VIRTUAL_ENV D:\xuequn\venv HTTP_CACHE_CONTROL no - cache HTTP_CONNECTION keep - alive TEMP C:\Users\admin\AppData\Local\Temp REMOTE_ADDR 127.0 . 0.1 COMMONPROGRAMFILES(X86) C:\Program Files (x86)\Common Files PROCESSOR_ARCHITECTURE AMD64 wsgi.url_scheme http ALLUSERSPROFILE C:\ProgramData SERVER_PORT 80 LOCALAPPDATA C:\Users\admin\AppData\Local HOMEPATH \Users\admin PYCHARM_MATPLOTLIB_PORT 50538 PROGRAMW6432 C:\Program Files USERNAME admin HTTP_ACCEPT image / webp,image / apng,image / * , * / * ;q = 0.8 LOGONSERVER \\ADMIN - PC PROMPT (venv) $P$G COMSPEC C:\Windows\system32\cmd.exe PROGRAMDATA C:\ProgramData PYTHONPATH D:\install soft\pycharm\PyCharm 2018.1 . 4 \helpers\pycharm_matplotlib_backend;D:\xuequn wsgi.multithread True wsgi. input <socket._fileobject object at 0x0000000002900B10 > HTTP_USER_AGENT Mozilla / 5.0 (Windows NT 6.1 ; WOW64) AppleWebKit / 537.36 (KHTML, like Gecko) Chrome / 63.0 . 3239.84 Safari / 537.36 HTTP_HOST localhost SESSIONNAME Console PATHEXT .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC PATH_INFO / favicon.ico FP_NO_HOST_CHECK NO WINDIR C:\Windows wsgi.file_wrapper wsgiref.util.FileWrapper HTTP_ACCEPT_ENCODING gzip, deflate, br wsgi.version ( 1 , 0 ) APPDATA C:\Users\admin\AppData\Roaming HOMEDRIVE C: SERVER_NAME admin - PC wsgi.run_once False REMOTE_HOST admin - PC SYSTEMDRIVE C: GATEWAY_INTERFACE CGI / 1.1 HTTP_ACCEPT_LANGUAGE zh - CN,zh;q = 0.9 ,en;q = 0.8 PYCHARM_HOSTED 1 NUMBER_OF_PROCESSORS 4 _OLD_VIRTUAL_PROMPT $P$G PROCESSOR_LEVEL 6 HTTP_PRAGMA no - cache CONTENT_TYPE text / plain wsgi.errors < open file '<stderr>' , mode 'w' at 0x0000000001D62150 > COMMONPROGRAMW6432 C:\Program Files\Common Files OS Windows_NT PUBLIC C:\Users\Public USERPROFILE C:\Users\admin |
以上是实现了一个简单的请求和响应的过程,但是每次请求都是响应的固定不变的内容(hello world!)。现实当中,我们肯定希望是动态的内容,而且一般是通过请求不同的URL来返回不同的HTML内容。
所以,我们需要解决动态路由的问题。
从上面的基本信息中我们可以找到一个非常有用的信息:PATH_INFO。其实,这个变量就是代表了当前请求的URL。返回的内容我们可以很容易解决,通过函数返回不同的HTML内容就可以了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #coding:utf-8 from wsgiref.simple_server import make_server def user(): return [ '<h1>hello jay!</h1>' ] def test(): return [ '<h1>Just a test</h1>' ] url_map = { 'user' :user, 'test' :test} #Flask里面就是通过url_map进行URL对象保存 def application(environ, start_response): path = environ[ 'PATH_INFO' ].split( '/' )[ 1 ] start_response( '200 OK' , [( 'Content-Type' , 'text/html' )]) if path in url_map: #这里比较LowB了,Flask里面会把URL和视图函数进行绑定。 return url_map[path]() else : return [ "<h1>Page 404,not found!</h1>" .encode( "utf8" )] httpd = make_server('', 80 , application) print ( 'Serving HTTP on port 80...' ) # 开始监听HTTP请求: httpd.serve_forever() |
这样,我们就把用户通过不同URL访问的内容进行了不同的响应,效果如下:
当然,如果是真实环境下,我们会从数据库中获取数据,把固定的内容替换成可变的HTML内容,这样一个简单的web框架就成型了,是不是So easy?
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」