本文基于 django runsever

  • 入口

    • 执行 python manage.py runserver

      • 调用 django.core.management.commands.runserver.Command.handle
      • 文件 runserver.py(django/core/management/commands/runserver.py)
  • 启动 TCP server
    • 从上面 handle 会进入 django.core.servers.basehttp.run
# 其中 server_cls 为 WSGIServer
def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer):
server_address = (addr, port)
if threading:
httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {})
else:
httpd_cls = server_cls
httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
if threading:
# ThreadingMixIn.daemon_threads indicates how threads will behave on an
# abrupt shutdown; like quitting the server by the user or restarting
# by the auto-reloader. True means the server will not wait for thread
# termination before it quits. This will make auto-reloader faster
# and will prevent the need to kill the server manually if a thread
# isn't terminating correctly.
httpd.daemon_threads = True
# wsgi_handler 为 settings.WSGI_APPLICATION 一般为 product_name/wsgi.py 中的 application
httpd.set_app(wsgi_handler) # httpd_cls.application = application 在后面 get_app 方法中会获取到
httpd.serve_forever()
  • 进入 server_forever
# socketserver.BaseServer.serve_forever
def serve_forever(self, poll_interval=0.5):
"""Handle one request at a time until shutdown. Polls for shutdown every poll_interval seconds. Ignores
self.timeout. If you need to do periodic tasks, do them in
another thread.
"""
self.__is_shut_down.clear()
try:
# XXX: Consider using another file descriptor or connecting to the
# socket to wake this up instead of polling. Polling reduces our
# responsiveness to a shutdown request and wastes cpu at all other
# times.
with _ServerSelector() as selector:
selector.register(self, selectors.EVENT_READ) while not self.__shutdown_request:
ready = selector.select(poll_interval)
# bpo-35017: shutdown() called during select(), exit immediately.
if self.__shutdown_request:
break
if ready:
self._handle_request_noblock() self.service_actions()
finally:
self.__shutdown_request = False
self.__is_shut_down.set()
  • 接下来进入 self._handle_request_noblock()
# socketserver.BaseServer._handle_request_noblock
def _handle_request_noblock(self):
"""Handle one request, without blocking. I assume that selector.select() has returned that the socket is
readable before this function was called, so there should be no risk of
blocking in get_request().
"""
try:
request, client_address = self.get_request()
except OSError:
return
if self.verify_request(request, client_address):
try:
self.process_request(request, client_address)
except Exception:
self.handle_error(request, client_address)
self.shutdown_request(request)
except:
self.shutdown_request(request)
raise
else:
self.shutdown_request(request)

其中 request, client_address = self.get_request(), 这时候 request 还只是一个 socket 对象

# socketserver.TCPServer.get_request
def get_request(self):
"""Get the request and client address from the socket. May be overridden. """
return self.socket.accept()
  • 处理请求 self.process_request(request, client_address)
# socketserver.BaseServer.process_request
def process_request(self, request, client_address):
"""Call finish_request. Overridden by ForkingMixIn and ThreadingMixIn. """
self.finish_request(request, client_address)
self.shutdown_request(request)
  • 完成一个 request self.finish_request(request, client_address)
# socketserver.BaseServer.finish_request
def finish_request(self, request, client_address):
"""Finish one request by instantiating RequestHandlerClass."""
self.RequestHandlerClass(request, client_address, self)

其中 RequestHandlerClass 为 WSGIRequestHandler (django.core.servers.basehttp.WSGIRequestHandler)

注意: 这时候 request 还只是一个 socket 对象 <class 'socket.socket'>

  • 实例化 handler socketserver.BaseRequestHandler
# socketserver.BaseRequestHandler
def __init__(self, request, client_address, server):
self.request = request
self.client_address = client_address
self.server = server
self.setup()
try:
self.handle()
finally:
self.finish()

其中 self.handle

# django.core.servers.basehttp.WSGIRequestHandler.handle
def handle(self):
self.close_connection = True
self.handle_one_request()
while not self.close_connection:
self.handle_one_request()
try:
self.connection.shutdown(socket.SHUT_WR)
except (socket.error, AttributeError):
pass
  • 从请求中获取信息 self.handle_one_request()
# django.core.servers.basehttp.WSGIRequestHandler.handle_one_request
def handle_one_request(self):
"""Copy of WSGIRequestHandler.handle() but with different ServerHandler"""
self.raw_requestline = self.rfile.readline(65537)
if len(self.raw_requestline) > 65536:
self.requestline = ''
self.request_version = ''
self.command = ''
self.send_error(414)
return if not self.parse_request(): # An error code has been sent, just exit
return handler = ServerHandler(
self.rfile, self.wfile, self.get_stderr(), self.get_environ()
)
handler.request_handler = self # backpointer for logging & connection closing
handler.run(self.server.get_app()) # 对应上面的 set_app

其中 ServerHandler 实例化中没有做特殊的操作

# django.core.servers.basehttp.ServerHandler
pass

run

# wsgiref.handlers.BaseHandler.run
# application 则是上面的 get_app 拿到的结果
def run(self, application):
"""Invoke the application"""
# Note to self: don't move the close()! Asynchronous servers shouldn't
# call close() from finish_response(), so if you close() anywhere but
# the double-error branch here, you'll break asynchronous servers by
# prematurely closing. Async servers must return from 'run()' without
# closing if there might still be output to iterate over.
try:
self.setup_environ()
self.result = application(self.environ, self.start_response)
self.finish_response()
except:
try:
self.handle_error()
except:
# If we get an error handling an error, just give up already!
self.close()
raise # ...and let the actual server figure it out.

调用 handler 的 __call__

  • 上面的 application 其实就是 product/wsgi.py 中的 application 最终拿到的是 WSGIHandler 的一个实例
# django.core.handlers.wsgi.WSGIHandler
class WSGIHandler(base.BaseHandler):
request_class = WSGIRequest def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.load_middleware() def __call__(self, environ, start_response):
set_script_prefix(get_script_name(environ))
signals.request_started.send(sender=self.__class__, environ=environ) # 发送 request_started 信号
request = self.request_class(environ) # 实例化 WSGIRequest 得到 django 中 view 中真实的 request
response = self.get_response(request) # 获取 response 会进入 middleware response._handler_class = self.__class__ status = '%d %s' % (response.status_code, response.reason_phrase)
response_headers = list(response.items())
for c in response.cookies.values():
response_headers.append(('Set-Cookie', c.output(header='')))
start_response(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
  • 实例化 Request
# django.core.handlers.wsgi.WSGIRequest
pass
  • 获取 response
# django.core.handlers.base.BaseHandler.get_response
def get_response(self, request):
"""Return an HttpResponse object for the given HttpRequest."""
# Setup default url resolver for this thread
set_urlconf(settings.ROOT_URLCONF) response = self._middleware_chain(request) response._closable_objects.append(request) # If the exception handler returns a TemplateResponse that has not
# been rendered, force it to be rendered.
if not getattr(response, 'is_rendered', True) and callable(getattr(response, 'render', None)):
response = response.render() if response.status_code >= 400:
log_response(
'%s: %s', response.reason_phrase, request.path,
response=response,
request=request,
) return response

接着回到 run

  • 关注下 self.finish_response()
# wsgiref.handlers.BaseHandler.finish_response
def finish_response(self):
"""Send any iterable data, then close self and the iterable Subclasses intended for use in asynchronous servers will
want to redefine this method, such that it sets up callbacks
in the event loop to iterate over the data, and to call
'self.close()' once the response is finished.
"""
try:
if not self.result_is_file() or not self.sendfile():
for data in self.result:
self.write(data)
self.finish_content()
finally:
self.close() # 其中 self.write
# wsgiref.handlers.BaseHandler.write
def write(self, data):
"""'write()' callable as specified by PEP 3333""" assert type(data) is bytes, \
"write() argument must be a bytes instance" if not self.status:
raise AssertionError("write() before start_response()") elif not self.headers_sent:
# Before the first output, send the stored headers
self.bytes_sent = len(data) # make sure we know content-length
self.send_headers()
else:
self.bytes_sent += len(data) # XXX check Content-Length and truncate if too many bytes written?
self._write(data)
self._flush() # 其中 self._write
# wsgiref.handlers.SimpleHandler._write
def _write(self,data):
result = self.stdout.write(data)
if result is None or result == len(data):
return
from warnings import warn
warn("SimpleHandler.stdout.write() should not do partial writes",
DeprecationWarning)
while True:
data = data[result:]
if not data:
break
result = self.stdout.write(data) # 其中 result = self.stdout.write(data)
def write(self, b):
self._sock.sendall(b)
with memoryview(b) as view:
return view.nbytes

django 处理请求的更多相关文章

  1. Django中请求的生命周期

    1. 概述 首先我们知道HTTP请求及服务端响应中传输的所有数据都是字符串. 在Django中,当我们访问一个的url时,会通过路由匹配进入相应的html网页中. Django的请求生命周期是指当用户 ...

  2. django 前端请求跨域问题解决

    django 前端请求跨域问题解决 笔者之前在做django-restful-api开发的时候,在前端请求页面发送请求的时候直接出现301,域名重定向的问题,经过一番查阅资料,终于得到了非常完美的解决 ...

  3. Django的请求生命周期

    Django的请求生命周期 请求生命周期 请求生命周期是指当用户在浏览器上输入url到用户看到网页的这个时间段内,Django后台所发生的事情. 1.客户端发送Http请求 2 .服务器接收,根据请求 ...

  4. Django 框架 django的请求生命周期

    概述 首先我们知道HTTP请求及服务端响应中传输的所有数据都是字符串,同时http请求是无状态的,可以通过session和cookie来辅助. 浏览器通过ip和端口及路由方式访问服务端. 在Djang ...

  5. django从请求到返回都经历了什么[转]

    原文地址:http://projectsedu.com/2016/10/17/django从请求到返回都经历了什么/ 从runserver说起 ruserver是使用django自己的web serv ...

  6. [oldboy-django][2深入django]django一个请求的生命周期 + WSGI + 中间件

    1 WSGI # WSGI(是一套协议,很多东西比如wsgiref, uwsgiref遵循这一套协议) - django系统本质 别人的socket(wsgiref或者uwsgiref) + djan ...

  7. DRF框架(一)——restful接口规范、基于规范下使用原生django接口查询和增加、原生Django CBV请求生命周期源码分析、drf请求生命周期源码分析、请求模块request、渲染模块render

    DRF框架    全称:django-rest framework 知识点 1.接口:什么是接口.restful接口规范 2.CBV生命周期源码 - 基于restful规范下的CBV接口 3.请求组件 ...

  8. Django - 获取请求方式

    //获取请过来得得请求类型 method = request.method 通过Django 的form 判断用户输入是否通过验证 check = forms.LoginFrom(request.PO ...

  9. [原]Django慢请求分析工具--dogslow

    当你的网站突然变慢了,你怎么办? 先看监控,查看系统的资源消耗,CPU?IO?磁盘? 然后看日志,查看第一个出现慢请求的接口是哪个? 然后看依赖的服务,是第三方服务还是DB瓶颈,还是redis变慢,还 ...

  10. django HTTP请求(Request)和回应(Response)对象

    Django使用request和response对象在系统间传递状态.—(阿伦)当一个页面被请示时,Django创建一个包含请求元数据的 HttpRequest 对象. 然后Django调入合适的视图 ...

随机推荐

  1. EXECL函数

    1 COUNTIF 对比两列数据,有相同的即计为1 找一列空白列,输入=COUNTIF(范围,条件),按回车,然后再点击表格右下角的"+" 就可以拉动持续执行这个函数 2 CONC ...

  2. (error) MOVED 12706 10.176.246.204:9736

    使用redis-cli连接上redis后,执行get命令报错: (error) MOVED 12706 10.176.246.204:9736 百度到原因是未以集群模式连接,在连接时加上-c参数就可以 ...

  3. Three.js 入门

    Demo代码地址: https://gitee.com/s0611163/three.js-demo Three.js Three.js下载 从GitHub上下载一个Release版本,https:/ ...

  4. C++:如何将 LLVM 嵌套到你的项目中去

    IDE: Clion LLVM cmake_minimum_required(VERSION 3.9) project(clang_demo) find_package(LLVM REQUIRED C ...

  5. #2054:A == B ?(水题坑人)

    Problem Description Give you two numbers A and B, if A is equal to B, you should print "YES&quo ...

  6. HHKB Programming Contest 2020 补题记录(D题投影,E题预处理节省时间)

    补题链接:Here A - Keyboard 签到,S 为 Y 则输出大写 T,不然则原样输出 T int main() { ios_base::sync_with_stdio(false), cin ...

  7. <vue 基础知识 2、插值语法> v-once,v-html,v-text,v-pre,v-cloak

    代码结构 一.     Mustache 1.效果 展示如何将数据展示在页面上 2.代码 01-Mustache.html <!DOCTYPE html> <html lang=&q ...

  8. CSS - 使图片自适应

    img {         height: 100%;         object-fit: cover; }

  9. Shell-基本

  10. 【wayn商城】本地开发指南

    这篇文章给大家带来我自己写的开源项目[wayn商城]的本地开发指南,帮助各位朋友在本地快速运行[wayn商城],避免踩坑,减少不必要的精力在软件下载安装上. waynboot-mall 是一套全部开源 ...