WSGI
WSGI 是 Web Server Gateway Interface 的缩写。是 Web 服务器如 Apache、Nginx 等与应用服务器(Application)进行交互的约定接口和规范。应用服务器通过实现该接口,可以与任意遵守该规范的 Web Server 通信。
eventlet.wsgi.py
提供基础的文件流读写,HTTP
报文头的解析与写入(HttpProtocol
实现),并实现了一个简单的 Server
包装类(包含了 Server
常见的 socket
,address
,keepalive
等,并简单的将请求转发给 HttpProtocol
来处理)。并在这个文件中,提供启动HTTP Sever
的功能函数,在这个函数中开启事件循环和 socket
监听,代码如下(在 Server 函数中):
其中HttpProtocol
类维护从socket
的conn
中获得的读写文件实例rfile, wfile
,并从中进行读写数据。这个类中handle_one_request
函数完成简单的HTTP
报文头校验,然后调用handle_one_response
方法获取 response
。handle_one_response
函数利用self.application
函数调用保存的WSGI Application
来完成对应的业务逻辑,然后将Application
返回的结果result
写入HTTP
请求头信息,最后写入到wfile
中。
nova.wsgi.py
包含几个主要的类:Server
、Application
、Middleware 和 Router
。其中 Server
维护了 host
、port
、protocol
、pool_size
等参数,作为一个通用的Socket Server
来使用,可以通过指定不同的 protocol
来启动不同的 socket
服务。并提供了start
、stop
和wait
来管理服务器的状态。Server
的Start
方法可以启动一个eventlet.wsgi.server
:
def start(self):
"""Start serving a WSGI application.
:returns: None
"""
# The server socket object will be closed after server exits,
# but the underlying file descriptor will remain open, and will
# give bad file descriptor error. So duplicating the socket object,
# to keep file descriptor usable.
dup_socket = self._socket.dup()
dup_socket.setsockopt(socket.SOL_SOCKET,
socket.SO_REUSEADDR, 1)
# sockets can hang around forever without keepalive
dup_socket.setsockopt(socket.SOL_SOCKET,
socket.SO_KEEPALIVE, 1)
...
wsgi_kwargs = {
'func': eventlet.wsgi.server,
'sock': dup_socket,
'site': self.app,
'protocol': self._protocol,
'custom_pool': self._pool,
'log': self._logger,
'log_format': CONF.wsgi.wsgi_log_format,
'debug': False,
'keepalive': CONF.wsgi.keep_alive,
'socket_timeout': self.client_socket_timeout
}
if self._max_url_len:
wsgi_kwargs['url_length_limit'] = self._max_url_len
self._server = utils.spawn(**wsgi_kwargs)
Application
仅定义了一个 WSGI
Application 的接口,主要是__call__
函数的接口,Application
的子类都要通过wsgify
装饰器来装饰__call__
方法,使其行为表现的像一个 WSGI Application
。
Middleware 继承了 Application
,意味着Middleware
可以表现的像一个Application
。同时也保存了一个 Application
成员引用,Middleware
作为 request
处理流程中的中间件。默认 Middleware
以函数形式调用,执行__call__
函数然后调用 self.application
使用内置 Application
。同时值得注意的是,Middleware
的__call__
使用webob.dec.wsgify
来进行修饰。webob.dec.wsgify
类是一个装饰器,将被装饰函数func
进行装饰,使func
表现为一个WSGI Application
。具体来说,webob.dec.wsgify
中的 __call__
函数,也是装饰器实现装饰功能的地方,会将传进的参数req
包装为webob.Request
对象,
environ = req
start_response = args[0]
req = self.RequestClass(environ)
req.response = req.ResponseClass()
try:
args, kw = self._prepare_args(None, None)
resp = self.call_func(req, *args, **kw)
except HTTPException as exc:
resp = exc
然后在self.call_func
函数中调用func
函数,再将返回结果包装为Response
对象:
if isinstance(resp, bytes):
body = resp
resp = req.response
resp.write(body)
if resp is not req.response:
resp = req.response.merge_cookies(resp)
return resp(environ, start_response)
值得注意的是,Middleware
可以利用`wsgify'装饰器来实现装饰器模式,在源代码中,可能还同时作为责任链模式的实现,用于链式处理请求。Router
类负责将url
映射到对应的controller
,并完成请求分发。
nova.api.openstack.wsgi.py
该文件中包含了Resource
类、Controller
类、action
、ControllerMetaclass
类以及Request
类。其中Resource
类继承自wsgi.Application
,包含一个controller
成员变量。负责根据请求从路由信息中找到对应的method
去执行。这当中涉及到action
的路由问题。具体的会调用Resource
的__call__
方法,在该方法中调用_process_task
方法查找具体的method
来执行。ControllerMetaclass
类主要工作是完成action
到method
的映射构建。Controller
类看不出他的作用,作为一个Controller
的基类。