首页 » 网站推广 » phpenv赋值技巧_Werkzeug源码分析

phpenv赋值技巧_Werkzeug源码分析

访客 2024-12-09 0

扫一扫用手机浏览

文章目录 [+]

def make_server( host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler): """Create a new WSGI server listening on `host` and `port` for `app`""" server = server_class((host, port), handler_class) server.set_app(app) #设置可调用运用 return server

该函数接在吸收到host和port后,为该运用程序指定了WSGI做事器,用于吸收要求,同时指定了处理该要求的类WSGIRequestHandler。

3.Werkzeug中间件(middleware)要求相应封装(wrappers)非常类本地高下文(local)路由(routing)3.1 middlewaredispatcher 程序调度中间件

#客户端 from werkzeug.middleware.dispatcher import DispatcherMiddleware def app1(env, start_response): start_response('200 OK', [('Content-Type', 'application/json')]) return str(env['wsgi.run_once']) def app2(env, start_response): start_response('200 OK', [('Content-Type', 'application/json')]) return str(env['wsgi.input']) app = DispatcherMiddleware(app1, {'/12': app2}) ''' 实现了call方法,吸收env和start_response参数 ''' # 做事端 from werkzeug.serving import run_simple from client import app run_simple('localhost', 9090, app, use_reloader=True)

对付不同的要求分配到不同的WSGI运用进行处理,默认要求的运用是app1,若要求以/12结尾,则会要求app2运用。
run_simple 内部调用两个方法(make_server 和serve_forever),利用的默认吸收要乞降处理要求的类是BaseWSGIServer、WSGIRequestHandler

phpenv赋值技巧_Werkzeug源码分析

http_proxy 代理中间件 (用于要求外部做事器)

from werkzeug.middleware.http_proxy import ProxyMiddlewaredef app1(env, start_response): start_response('200 OK', [('Content-Type', 'application/json')]) return str(env['wsgi.run_once'])app = ProxyMiddleware(app1, {'/12/': { 'target':"http://localhost:9000",}})

ProxyMiddleware的call方法

phpenv赋值技巧_Werkzeug源码分析
(图片来自网络侵删)

def __call__(self, environ, start_response): path = environ["PATH_INFO"] app = self.app for prefix, opts in self.targets.items(): if path.startswith(prefix): app = self.proxy_to(opts, path, prefix) break return app(environ, start_response)#proxy_toproxy_to 构建外部做事器的要求if target.scheme == "http": con = client.HTTPConnection( target.ascii_host, target.port or 80, timeout=self.timeout )elif target.scheme == "https": con = client.HTTPSConnection( target.ascii_host, target.port or 443, timeout=self.timeout, context=opts["ssl_context"], )else: raise RuntimeError( "Target scheme must be 'http' or 'https', got '{}'.".format( target.scheme ) )con.connect()shared_data 静态资源访问中间件

from werkzeug.middleware.shared_data import SharedDataMiddlewareimport osdef app1(env, start_response): start_response('200 OK', [('Content-Type', 'application/json')]) return str(env['wsgi.run_once'])app = SharedDataMiddleware(app1, {'/static':os.path.join(os.path.dirname(__file__),'1.jpg')})#若在做事端条件了参数static_files,则客户端可以不该用SharedDataMiddleware中间件if static_files: from .middleware.shared_data import SharedDataMiddleware application = SharedDataMiddleware(application, static_files)

SharedDataMiddleware的call方法紧张代码为:wrap_file(environ, f) f为文件句柄,其实际实行了一个FileWrapper文件装饰器,其内部实现了迭代器的协议方法

def __iter__(self): return selfdef __next__(self): data = self.file.read(self.buffer_size) if data: return data raise StopIteration()3.2 wrappers

from werkzeug.wrappers import Request,Response#办法1def app(env, start_response): request = Request(env) resp = Response('hello werkzeug from ' + str(request.environ)) return resp(env, start_response)#办法2@Request.applicationdef app1(request): return Response('hello werkzeug from '+ str(request.environ['HTTP_USER_AGENT']))

对付办法1,Request类对env进行包装,将env赋值给其属性变量environ,返回的resp是一个知足wsgi协议的运用。

def __call__(self, environ, start_response): """Process this response as WSGI application. :param environ: the WSGI environment. :param start_response: the response callable provided by the WSGI server. :return: an application iterator """ app_iter, status, headers = self.get_wsgi_response(environ) start_response(status, headers) return app_iter

对付办法2,利用到了装饰器,个中Request类的application是一个类方法classmethod,其内部函数为:

'''f即为被装饰的函数```app1```, 位置参数args为支持wsgi协议的默认运用入口的参数(environ,start_response)。
'''@classmethod def application(cls, f): def application(args): request = cls(args[-2]) #等价于Request(environ) with request: try: #移除原协议参数,同时将request作为要求参数,即为原app1(request) resp = f(args[:-2] + (request,)) except HTTPException as e: resp = e.get_response(args[-2]) return resp(args[-2:]) #即resp(environ,start_response) return update_wrapper(application, f) #update_wrapper 用于保留装饰后原函数的属性,即对(__dict__,__name__等)进行拷贝

办法2实在是实行办法1,是等价的。

request=Request(environ)包含一些吸收数据的方法

request.args 吸收get要求的参数,其类型为ImmutableMultiDict,不可变的多值字典工具,继续标准字典的所有方法。

第一种情形:当要求参数为一个键对应的多个值时,通过字典的方法,则只会取到第一组数据。
此时应利用ImmutableMultiDict的lists()方法拿到数据([('name', [u'123', u'222'])])第二种情形:键值对逐一对应,即可以通过lists()方法取数据,字典的方法取数据。

>>> d = MultiDict([('a', 'b'), ('a', 'c')]) >>> d MultiDict([('a', 'b'), ('a', 'c')]) >>> d['a'] 'b' >>> d.getlist('a') ['b', 'c'] >>> 'a' in d Truerequest.get_data()用于吸收post要求的参数,类型为字典序列化后的字符串。
如利用request.data吸收要求参数,则要求时须要指定contentType(非application/x-www-form-urlencoded),否则吸收到的数据为空。
3.3 local

本地高下文紧张利用到了协程greenlet, local其本色是在全局环境下,担保数据的隔离性,不同协程间的数据互不滋扰。

from werkzeug.local import Localfrom greenlet import getcurrent as get_ident , greenletl = Local()def t1(): l.a = 12 l.A = 34 print('协程t1:%s'% l.__ident_func__(), l.a) gr2.switch() l.la = 'greenlet'def t2(): l.b = 21 l.B = 43 print('协程t2:%s'% l.__ident_func__(), l.b) gr1.switch()if __name__ == "__main__": l.m = 8 l.M = 9 print('默认协程:%s'%l.__ident_func__(), l.m) gr1 = greenlet(t1) gr2 = greenlet(t2) gr1.switch() print('协程开辟独立空间存储的数据:') for k, v in l: print('%s==%s'%(k, v))

=out=

默认协程:<greenlet.greenlet object at 0x10f4b9c00> 8协程t1:<greenlet.greenlet object at 0x10f4b9e10> 12协程t2:<greenlet.greenlet object at 0x10f4b9ec0> 21协程开辟独立空间存储的数据:<greenlet.greenlet object at 0x10f4b9c00>=={'m': 8, 'M': 9}<greenlet.greenlet object at 0x10f4b9e10>=={'a': 12, 'A': 34, 'la': 'greenlet'}<greenlet.greenlet object at 0x10f4b9ec0>=={'b': 21, 'B': 43}

local内部实现了( Local, LocalStack )来实现数据的隔离,实质上是字典,只是字典的键为协程的id。

try: from greenlet import getcurrent as get_identexcept ImportError: try: from thread import get_ident except ImportError: from _thread import get_identclass Local(object): __slots__ = ("__storage__", "__ident_func__") def __init__(self): object.__setattr__(self, "__storage__", {}) object.__setattr__(self, "__ident_func__", get_ident) def __release_local__(self): #协程实行完开释数据存储空间 self.__storage__.pop(self.__ident_func__(), None)

LocalManager是对local工具进行管理,其紧张的功能便是存储要求数据,及完成要求后,对存储空间进行资源开释。

from werkzeug.local import Local, LocalManagerfrom werkzeug.wrappers import Request, Responselocal = Local()local_manager = LocalManager(local)def app(env, start_response): local.request = request = Request(env) resp = Response('hello werkzeug from ' + str(request.environ)) for k, v in local: print(k, v) return resp(env, start_response)app = local_manager.middleware(app)

对app进行重新赋值,目的是担保要求完成后,及时打消存储于local中的数据。
实在质是实行ClosingIterator(app(environ, start_response), self.cleanup), 其内部实现了迭代器协议和close方法该方法用于实行self.cleanup,即对要求存储在local中的数据进行打消。

3.4 routing

供应了变量转换器(Converter)、路由匹配规则(Rule)、存储路由规则(Map)、Map适配器(MapAdapter),目的是通过不同的path_info 路径匹配对应的规则或函数

from werkzeug.routing import Map, Rulefrom werkzeug.wrappers import Request, Responsedef get_message(request): return Response('路由'+ str(request.environ))def get_number(request): return Response('123') rule1 = Rule('/message', endpoint=get_message) #建立路径到视图的映射rule2 = Rule('/number', endpoint=get_number)url_map = Map([rule1, rule2]) #存储路由映射def app(env, start_response): request = Request(env) adapter = url_map.bind_to_environ(env) #1 endpoint, values = adapter.match() #2 resp = endpoint(request) return resp(env, start_response)

解析

是完成要求环境的绑定,用于获取要求的方法、协议、要求参数等信息,并将获取的要求干系信息作为参数通报给MapAdapter。
是完成要求参数和路由映射的匹配(实质上实行了rule的match方法),并对要求方法进行检讨

for rule in self.map._rules: try: rv = rule.match(path, method) #3 except RequestSlash :#内部要求缺点 ....... if rv is None: continue if rule.methods is not None and method not in rule.methods: have_match_for.update(rule.methods) return rule.endpoint, rv if have_match_for: #路由迭代完成后,如果存在have_match_for,会报MethodNotAllowed缺点 raise MethodNotAllowed(valid_methods=list(have_match_for)) raise NotFound()是对要求的路径和路由进行一个正则匹配,并返回携带的要求路径动态参数,若没有动态参数,则返回空字典;如果返回的rv为None,则表示Path_info路径没有和当前的路由规则匹配上。

#rule.match核心代码 m = self._regex.search(path) if m is not None: groups = m.groupdict() # 动态路径字典 ..........

标签:

相关文章