Django WSGI 初探
起步#
在第一章说到,django 使用 WSGIServer
作为内置服务器软件,这个类的实现在 django/core/servers/basehttp.py
文件中定义,这个类继承自 wsgiref.simple_server.WSGIServer
。django中自带的各种 ServerHandler
, WSGIServer
, WSGIRequestHandler
都基于自python模块 wsgiref
进行及其简单的封装而成的。
Django 的内置服务器#
Django 内置服务器在 django.core.servers
和 django.core.handlers
, 这两者共同来实现。它们基本都是基于 wsgiref.simple_server
继承过来的,关于python本身的标准库中的模块我们就不分析了,这个模块里大致就是从文本级别的解析http包。 从 django.core.servers.basehttp
中:
def run(addr, port, wsgi_handler, ipv6=False, threading=False):
server_address = (addr, port)
if threading:
httpd_cls = type(str('WSGIServer'), (socketserver.ThreadingMixIn, WSGIServer), {})
else:
httpd_cls = WSGIServer
httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
if threading:
httpd.daemon_threads = True
httpd.set_app(wsgi_handler)
httpd.serve_forever() # 长期运行
这里的 wsgi_handler
变量是一个 StaticFilesHandler
实例(下文提到)。
WSGI 应用#
作为第一个作为wsgi应用,它的定义是在 settings.py
中有个项:
WSGI_APPLICATION = 'webui.wsgi.application'
打开其同目录下的 wsgi.py
:
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "webui.settings")
application = get_wsgi_application()
get_wsgi_application()
中实例化了 django.core.handlers.wsgi.WSGIHandler
, 并无其他操作。wsgi通过 ServerHandler
来执行django的应用程序,第一个落地对象是 StaticFilesHandler
,从 runserver 的命令执行器 django.contrib.staticfiles.management.commands.runserver
可以得到:
class Command(RunserverCommand):
...
def get_handler(self, *args, **options):
handler = super(Command, self).get_handler(*args, **options) # handle 即上述中 WSGIHandler 的实例
use_static_handler = options['use_static_handler']
insecure_serving = options['insecure_serving']
if use_static_handler and (settings.DEBUG or insecure_serving):
return StaticFilesHandler(handler)
return handler
简单看看 StaticFilesHandler
的构成:
class StaticFilesHandler(WSGIHandler):
def __init__(self, application):
self.application = application
self.base_url = urlparse(self.get_base_url())
super(StaticFilesHandler, self).__init__()
def _should_handle(self, path): # 是否是静态文件
return path.startswith(self.base_url[2]) and not self.base_url[1]
def __call__(self, environ, start_response):
if not self._should_handle(get_path_info(environ)):# 如果不是静态文件,交给wsgi应用处理
return self.application(environ, start_response)
return super(StaticFilesHandler, self).__call__(environ, start_response)
StaticFilesHandler
的作用是当请求出现时,先检查url是不是一个静态文件请求,如果是的话则进入静态文件(图片、css样式文件、js脚本文件等等)处理的view,如果不是的话则将该请求提交给Django的handler来进行处理(解析url、执行对应的view代码块、渲染和返回template)。
当请求不是静态文件时候,就调用 self.application(environ, start_response)
,也就是 django.core.handlers.wsgi.WSGIHandler
中定义的 __call__
方法:
class WSGIHandler(base.BaseHandler):
request_class = WSGIRequest
def __call__(self, environ, start_response):
try:
# 实例化 WSGIRequest
request = self.request_class(environ)
except UnicodeDecodeError:
response = http.HttpResponseBadRequest()
else:
# 调用 self.get_response(), 将会返回一个相应对象 response
response = self.get_response(request)
response._handler_class = self.__class__ # 将 self 挂钩到 response 对象
status = '%d %s' % (response.status_code, response.reason_phrase)
response_headers = [(str(k), str(v)) for k, v in response.items()]
for c in response.cookies.values():
response_headers.append((str('Set-Cookie'), str(c.output(header=''))))
start_response(force_str(status), response_headers)
if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):
response = environ['wsgi.file_wrapper'](response.file_to_stream)
return response
这个 __call__
中主要做了两件事,一个是根据字典 environ
实例化了一个 WSGIRequest 对象 request = self.request_class(environ)
,这个也就是开发django中,view视图中作为参数的那个 request
。这个对象是根据wsgi接口中的WSGIRequestHandler
中的 get_environ()
方法做的工作,针对 environ
进行预处理(例如header、PATH_INFO、REQUEST_METHOD、charset等等。
第二件事是获得 reponse 对象 self.get_response(request)
,有意思的是,在其父类的 get_response
中,通过中间件的机制,执行的可能是 django.contrib.staticfiles.StaticFilesHandler
, 也可能是 django.core.handlers.wsgi.WSGIHandler
等。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架