Django 一次请求从进入到返回响应经历了哪些流程?
简化版
Django 请求流程大致是:Web 服务器把请求交给 WSGI/ASGI 应用,Django 创建 HttpRequest,按顺序执行请求阶段中间件,URLconf 匹配视图,视图处理业务并返回 HttpResponse,再经过响应阶段中间件,最后把响应交回客户端。
详细版
一次典型 Django 请求可以拆成几个阶段:
- 入口层:Nginx/Gunicorn/uWSGI/Daphne/Uvicorn 等把 HTTP 请求交给 Django 的 WSGI 或 ASGI 应用。
- 请求对象:Django 封装
HttpRequest,里面包含路径、方法、GET/POST 参数、Header、Session、User 等信息。 - 中间件请求阶段:按
MIDDLEWARE配置顺序执行,例如安全、Session、认证、CSRF 等。 - URL 匹配:根据
ROOT_URLCONF找到匹配的路由和对应视图。 - 视图执行:视图函数或类视图读取请求、访问数据库、调用业务逻辑,返回响应对象。
- 模板渲染:如果用
render(),会把模板和上下文数据渲染成 HTML。 - 中间件响应阶段:按相反方向处理响应,例如设置 Cookie、压缩、添加安全 Header。
- 返回客户端:最终
HttpResponse被服务器发送给浏览器或调用方。
面试重点是说清楚中间件、URLconf、View 三者的位置,以及异常会被中间件和 Django 异常处理机制捕获并转换成合适响应。
完整版教学
一、入口:Django 不直接监听公网端口
生产环境里,Django 通常不会直接暴露给公网,而是放在 Web 服务器或应用服务器后面:
浏览器 → Nginx → Gunicorn/uWSGI/Uvicorn → Django
如果是传统同步项目,常见入口是 WSGI;如果使用异步视图、WebSocket 相关生态,常见入口是 ASGI。Django 同时支持 WSGI 和 ASGI,但并不意味着所有代码天然异步,是否真正异步还要看视图、中间件、数据库访问方式等。
二、请求对象:HttpRequest 是视图拿信息的入口
视图函数的第一个参数通常是 request:
def profile(request):
user = request.user
page = request.GET.get("page", "1")
return render(request, "profile.html", {"user": user, "page": page})
request 里常用内容包括:
request.method:GET、POST、PUT 等;request.GET:查询字符串参数;request.POST:表单提交数据;request.headers:请求头;request.COOKIES:Cookie;request.session:会话数据;request.user:认证用户对象。
其中 session 和 user 并不是凭空出现的,通常依赖 SessionMiddleware 和 AuthenticationMiddleware。
三、中间件:请求进来顺序执行,响应回去反向执行
中间件是包在视图外层的一圈处理逻辑。假设配置如下:
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
]
请求进入时大致按列表顺序走,响应返回时按反向顺序走。这一点非常重要,因为顺序错了会导致一些对象还没准备好。例如 AuthenticationMiddleware 依赖 SessionMiddleware 提供 session 能力,所以认证中间件通常要放在 session 中间件之后。
中间件适合做横切逻辑:安全 Header、Session、认证、CSRF、日志、限流、异常包装。不要把具体业务流程塞进全局中间件,否则会让请求链路变得难以理解。
四、URLconf:把路径分发给视图
URLconf 的职责是匹配路径:
urlpatterns = [
path("users/<int:user_id>/", views.user_detail, name="user_detail"),
]
当请求 /users/10/ 时,Django 会解析出 user_id=10,并把它作为参数传给视图:
def user_detail(request, user_id):
...
URLconf 做的是路由分发,不应该包含复杂业务判断。业务规则放到视图、服务层或模型层更清晰。
五、视图:请求处理的核心
视图可以是函数,也可以是类:
from django.views import View
from django.http import JsonResponse
class UserDetailView(View):
def get(self, request, user_id):
return JsonResponse({"id": user_id})
类视图适合复用通用逻辑,例如列表、详情、创建、更新等;函数视图适合简单场景。面试时可以补一句:类视图不是性能更好,而是组织和复用能力更强。
六、异常与响应阶段
视图返回的必须是 HttpResponse 或其子类,例如 JsonResponse、HttpResponseRedirect。如果视图抛出 Http404、权限异常或未捕获异常,Django 会按配置返回 404、403、500 等页面。
响应阶段中间件可以修改响应,例如:
- 设置安全 Header;
- 写入 Session Cookie;
- 添加压缩;
- 记录访问日志;
- 统一包装响应。
七、面试追问:WSGI、ASGI 和同步异步怎么讲
面试官常会顺着请求流程追问 WSGI 和 ASGI。可以这样回答:WSGI 是 Python Web 应用和服务器之间的同步接口,适合传统 HTTP 请求;ASGI 是支持异步能力的接口,可以处理 HTTP,也能承载 WebSocket、长连接等场景。Django 从 3.x 开始支持 ASGI,但支持 ASGI 不等于所有代码都会自动异步。
如果一个 Django 项目里视图是同步函数、ORM 调用也是同步数据库驱动,那么即使用 ASGI 部署,也不能把阻塞数据库查询变成非阻塞。真正的异步链路要求视图、中间件、调用的 I/O 库都具备异步能力。面试时把这点说清楚,能避免“ASGI 一定高性能”这种误区。
生产部署里常见组合是:Nginx 负责静态资源、TLS、反向代理;Gunicorn/uWSGI 运行 WSGI 应用;Uvicorn/Daphne 运行 ASGI 应用。Django 的请求生命周期发生在应用服务器把请求交给 Django 之后,Nginx 层的限流、压缩、静态文件处理不属于 Django 内部流程。
八、工程排查:如何定位请求链路问题
真实项目里,请求流程不是背概念,而是用于排查问题。比如用户反馈登录后仍然未认证,可以检查 SessionMiddleware 和 AuthenticationMiddleware 的顺序、Cookie 是否写入、Session 后端是否正常;如果 POST 请求 403,可以检查 CSRF 中间件、模板 token、Header 是否正确;如果接口慢,可以从中间件日志、视图耗时、ORM SQL、模板渲染耗时逐层定位。
一个比较成熟的回答方式是:请求链路里每一层都可能出问题,入口层看代理和应用服务器,Django 层看中间件和 URLconf,业务层看视图和 ORM,响应层看 Cookie、Header、异常处理。能按链路排查,比只背“请求进来再返回”更接近工程实践。
九、常见误区与追问
| 阶段 | 关键对象 | 面试关注点 |
|---|---|---|
| 入口层 | WSGI/ASGI application | Django 接入应用服务器,不直接等同于 Nginx |
| 请求阶段 | HttpRequest、中间件、URLconf | 顺序、参数解析、认证会话来源 |
| 响应阶段 | HttpResponse、中间件反向返回 | Header、Cookie、异常页面、日志收尾 |
- 误区:Django 直接接收浏览器 TCP 连接。 生产环境通常由 Nginx、Gunicorn、uWSGI、Uvicorn 或 Daphne 等组件接入,再把请求交给 Django 应用。
- 误区:request.user 是 HttpRequest 天生就有的真实用户。 它通常由 SessionMiddleware 和 AuthenticationMiddleware 等中间件配合填充,未登录时可能是 AnonymousUser。
- 误区:中间件只在请求进来时执行。 新式中间件包裹视图,请求按配置顺序进入,响应按相反顺序返回。
- 追问:URLconf 在请求链路中做什么? 它根据路径和 path converter 匹配视图,并把解析出的参数传给视图函数或类视图。
- 追问:异常发生后还会经过中间件吗? Django 会把异常交给异常处理流程,能否被自定义中间件包装取决于中间件位置和写法,最终通常转成合适的 HTTP 响应。
- 追问:ASGI 部署就一定比 WSGI 快吗? 不一定;如果视图、ORM 调用和中间件仍是同步阻塞代码,ASGI 入口不会自动把链路变成非阻塞。
记忆钩子:请求链路按“入口、Request、中间件、路由、视图、Response、中间件返回”来串,面试时再补 WSGI/ASGI 和异常处理即可。
十、加强记忆
Django 请求链路可以记成“入口、请求、中间件、路由、视图、模板、响应、中间件返回”。其中中间件像洋葱皮,进来按配置顺序,出去反向返回;URLconf 负责找视图,View 负责处理业务并生成响应。