介绍
Werkzeug 并不是 一个框架,它是一个 WSGI 工具集的库,你可以通过它来创建你自己的框架或 Web 应用。
官方的介绍说是一个 WSGI 工具包,它可以作为一个 Web 框架的底层库,因为它封装好了很多 Web 框架的东西,例如 Request,Response 等等
例如我最常用的 Flask 框架就是一 Werkzeug 为基础开发的,这也是我要解析一下 Werkzeug 底层的原因,因为我想知道 Flask 的实现逻辑以及底层控制
werkzeug的简单使用
from werkzeug.serving import run_simple from werkzeug.wrappers import Response,Request @Request.application def app(request): print(request.method) return Response("hello world") run_simple("0.0.0.0",5000,app) #这里一运行,就执行app函数
Flask框架的上下文--源码
我们可以对比Flask,下面是flask的一个简单使用
1:第一阶段 封装Werkzeug 中 run_simple
from flask import Flask app = Flask(__name__) @app.route('/') #相当于Django中的url.py def hello_world(): #视图函数相当于Django中的setting.py return 'Hello World!' if __name__ == '__main__': app.run()
下面查看这个app.run()的源码
def run(self, host=None, port=None, debug=None, load_dotenv=True, **options): ...... .............. from werkzeug.serving import run_simple try: run_simple(host, port, self, **options) #这里的self实际上是app,因为是app.run()
#self = app = Flask(),而一运行,就会执行self()相当于执行app(),那么就会运行Flask中__call__方法
def __call__(self, environ, start_response): return self.wsgi_app(environ, start_response) #environ是请求的原始信息
2:第二阶段 flask的上文
此阶段实际上是把请求的原始信息转换为request,并放入到一个大的空间结构中
(1)把原始信息转换为request,获得request、session
def wsgi_app(self, environ, start_response): ctx = self.request_context(environ) #environ是请求的原始信息,ctx最后结果是包含了request和session
def request_context(self, environ): return RequestContext(self, environ) #self = app = Flask()
class RequestContext(object): def __init__(self, app, environ, request=None): # self = request_context app = app =Flask() self.app = app if request is None: request = app.request_class(environ) #这就是把请求的原始信息处理成request app.request_class() 实际上执行了 Flask() self.request = request self.url_adapter = app.create_url_adapter(self.request) self.flashes = None self.session = None
app.request_class()
request_class = Request
class Request(BaseRequest, AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthorizationMixin, CommonRequestDescriptorsMixin):
class BaseRequest(object): def __init__(self, environ, populate_request=True, shallow=False): self.environ = environ if populate_request and not shallow: self.environ['werkzeug.request'] = self self.shallow = shallow
(2)把request放入大存储结构空间中
第一步:先生成数据结构
1 2 3 4 5 6 | def wsgi_app(self, environ, start_response): ctx = self.request_context(environ) error = None try: try: ctx.push() |
def push(self): #self:ctx--request session top = _request_ctx_stack.top #_request_ctx_stack是{'_local':{'__storage__':{},'__ident_func__':get_ident}}
a: _request_ctx_stack获取的是啥呢?
_request_ctx_stack = LocalStack() #{'_local':{'__storage__':{},'__ident_func__':get_ident}}
class LocalStack(object): def __init__(self): #self:LocalStack self._local = Local() #self._local ={'__storage__':{},'__ident_func__':get_ident}
try:
from greenlet import getcurrent as get_ident
except ImportError:
try:
from thread import get_ident
except ImportError:
from _thread import get_ident
class Local(object): __slots__ = ('__storage__', '__ident_func__') #插槽:表示这个类里只允许有这些属性 def __init__(self): object.__setattr__(self, '__storage__', {})#给Local自己设置一个__storage__的属性,值为{} object.__setattr__(self, '__ident_func__', get_ident) #get_ident是获取线程id
b: _request_ctx_stack.top()获取的是啥呢?
返回None
@property def top(self):#self是{'_local':{'__storage__':{},'__ident_func__':get_ident}}
try: return self._local.stack[-1] #执行__getattr__() except (AttributeError, IndexError): return None
获取结果__storage__ = {9527:{‘stack’:value}}
1 2 3 4 | class Local(object): def __getattr__(self, name): #name=stack try: return self.__storage__[self.__ident_func__()][name] #__ident_func__()是线程或携程id except KeyError: raise AttributeError(name) |
第二步:把request、session放入数据结构中
def push(self): app_ctx = _app_ctx_stack.top _request_ctx_stack.push(self) #_request_ctx_stack是{'_local':{'__storage__'{},'__ident_func__':get_ident}} #self = ctx - request \session = request_context
def push(self, obj): rv = getattr(self._local, 'stack', None) #rv=None if rv is None: self._local.stack = rv = [] #执行Local()的__setattr__
#之后self是{'_local':{'__storage__'{9527:{‘stack’:[]}},'__ident_func__':get_ident}}
rv.append(obj) #这个结果得到{'_local':{'__storage__'{9527:{‘stack’:[request session]}},'__ident_func__':get_ident}}
return rv
#self是{'_local':{'__storage__'{},'__ident_func__':get_ident}}
#obj = self = ctx - request \session = request_context
def __setattr__(self, name, value): #name=stack value=rv = [] ident = self.__ident_func__() #线程id storage = self.__storage__ #{} try: storage[ident][name] = value except KeyError: storage[ident] = {name: value} {9527:{‘stack’:[]}}
3:第三阶段 flask的下文
这一阶段实际上就是当我们使用request的时候的一个获取request的阶段
第一步:获取request对象的偏函数,但没有执行
from flask import request request.method
request = LocalProxy(partial(_lookup_req_object, 'request')) #偏函数
def _lookup_req_object(name): #name = request top = _request_ctx_stack.top if top is None: #top=request、session raise RuntimeError(_request_ctx_err_msg) return getattr(top, name) #拿出request对象
#{'_local':{'__storage__'{9527:{‘stack’:[request session]}},'__ident_func__':get_ident}}
@property def top(self): try: return self._local.stack[-1] #执行__getattr__,获取到request、session except (AttributeError, IndexError): return None
def __getattr__(self, name): try: return self.__storage__[self.__ident_func__()][name] #取出request、session except KeyError: raise AttributeError(name)
第二步:执行偏函数,真正获取request
初始化
@implements_bool class LocalProxy(object): __slots__ = ('__local', '__dict__', '__name__', '__wrapped__') def __init__(self, local, name=None):#local=_lookup_req_object=request偏函数
object.__setattr__(self, '_LocalProxy__local', local) #设置类属性 object.__setattr__(self, '__name__', name) if callable(local) and not hasattr(local, '__release_local__'): #callable(local)表示是否可执行,local是偏函数
object.__setattr__(self, '__wrapped__', local)
真正使用,request.method,执行LocalProxy类__getattr__方法
def __getattr__(self, name): #name=method if name == '__members__': return dir(self._get_current_object()) return getattr(self._get_current_object(), name) #从request对象里拿method
def _get_current_object(self): if not hasattr(self.__local, '__release_local__'): return self.__local() #执行偏函数 try: return getattr(self.__local, self.__name__) except AttributeError: raise RuntimeError('no object bound to %s' % self.__name__)
参考资料
https://werkzeug-docs-cn.readthedocs.io/zh_CN/latest/tutorial.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理