используется в этой статьеDjangoВерсия кода:2.1.3
Анализ, проведенный в данной статье, не ограничивается однимDjangoверсии, но постараюсь обсудить версию2.0+
Обзор процесса
Обзор:
Djangoи другиеWebобрамленныйHTTPПроцесс обработки примерно такой же: первый проходRequest MiddlewareОпределите объект запроса, а затем передайте значение по умолчаниюURLуказать на метод и, наконец, передатьResponse MiddlewareВыполните пользовательскую обработку объекта ответа.
Подробности:
- [Пуск->WSGI] Запустить любым способом
DjangoСоздайтеWSGIServerэкземпляр класса - Пользователь запрашивает определенный
Djangoстраница - [WSGI]
Django WSGIServerПолучить инициализацию запроса клиента (браузера)WSGIHandlerпример - [WSGI->Загрузить конфигурацию] Импорт
settingнастроить иDjangoкласс исключений - [WSGI->Промежуточное ПО] Загрузка
settingПО промежуточного слоя установлено в - [промежуточное ПО] создать
_request_middleware,_view_middleware,_response_middleware,_exception_middlewareчетыре списка - [Промежуточное ПО] Выполнение обхода
_request_middleware,правильноrequestПроцесс: если вернутьсяNoneПерейти к 8; если вернуться напрямуюHttpResponseОбъект переходит на 12 - [Преобразователь URL] разрешить
urlи сделать совпадение (при условии, что совпадение успешно) - [Промежуточное ПО] Выполнение обхода
_view_middleware,правильноrequestПроцесс: если вернутьсяNoneВведите до 10; если вернуться напрямуюHttpResponseОбъект переходит на 12. - [промежуточное ПО] реализация
urlсовпалоviewЛогика: если возникает исключение, перейти к 11; если оно возвращается нормальноHttpResponseОбъект переходит на 12 - [Промежуточное ПО] Выполнение обхода
_exception_middleware - [Промежуточное ПО] Выполнение обхода
_response_middleware,правильноHttpResponseпроцесс и, наконец, возвратresponse
запускать
В среде разработки мы обычно выполняем его через командную строку.runserverЗаказ,ruserverкоманда использоватьDjangoавтономныйWeb Server, а в формальной среде обычно используетсяNginx+uWSGIмодель.
В любом случае, когда вы начинаете проект, он делает две вещи:
- Создавать
WSGIServerЭкземпляр класса для приема пользовательских запросов. - когда пользователь
HTTPПри поступлении запроса укажитеWSGIHandler, используемый для обработки пользовательских запросов и ответов, этоHandlerзаключается в обработке всегоRequestОсновной.
WSGI
WSGI: полное имяWeb Server Gateway Interface.
WSGIне сервер,Pythonмодули, фреймворки,APIили любое программное обеспечение, просто спецификация, описывающаяWeb ServerКак работать сWeb ApplicationСпецификации для связи.
WSGIСоглашение в основном включаетserverиapplicationДве части:
-
WSGI ServerОтветственный за прием заявок от клиентов, будетrequestвперед кapplication,будетapplicationвозвращениеresponseвозврат клиенту; -
WSGI Applicationполученоserverперенаправленrequest, обработать запрос и вернуть результат обработки вserver.applicationОн может включать в себя несколько промежуточных программ стекового типа (промежуточных программ), которые необходимо внедрять одновременно.serverиapplication, так что может бытьWSGIсервер сWSGIМодерация между приложениями: для сервера промежуточное ПО действует как приложение, а для приложения промежуточное ПО действует как сервер.
Django WSGI Application
WSGI ApplicationДолжен быть реализован как вызываемый объект, такой как: функции, методы, классы (включаяcallметод).
Нужно получить два параметра:
- Словарь, содержащий запрошенную клиентом информацию, а также другую информацию. Его можно рассматривать как контекст запроса, обычно называемый
environment(В кодировании это часто сокращается какenviron,env); - для отправки
HTTPстатус ответа (HTTP Status), заголовки ответов (HTTP Headers) функция обратного вызова;
Верните статус ответа и заголовки ответа через функцию обратного вызова вWSGI Serverи возвращает тело ответа, которое является итерируемым и содержит несколько строк. НижеDjango WSGI ApplicationКонкретная реализация:
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 = self.request_class(environ)
response = self.get_response(request)
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='')))
# 本文作者注:将响应的 header 和 status 返回给 server
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
Как можно видетьDjango WSGI ApplicationПроцесс включает в себя:
- Загрузить все промежуточное ПО, выполнить операции, связанные с фреймворком, установить префикс сценария текущего потока и отправить сигнал запуска запроса;
- обработать заявку, позвонить
get_response()Метод обрабатывает текущий запрос, и основная логика этого метода заключается в следующем:urlconfнайти соответствующийviewиcallback, выполнять различныеmiddlewareиcallback; - вызванный
WSGI Serverвходящийstart_response()метод ответитheaderиstatusВернуться кWSGI Server; - Возвращает тело ответа.
Django WSGI Server
ответственный за получениеHTTPзапрос, передать запросDjango WSGI Application,Зависит отDjango WSGI Applicationвозврат после обработки запросаresponse. отDjangoвстроенныйserverВзгляните на конкретную реализацию в качестве примера.
пройти черезrunserverкоманда для запускаDjangoПроект вызовет следующее при запускеrunметод, создайтеWSGIServerэкземпляр , а затем вызовите егоserve_forever()способ запуска службы.
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:
httpd.daemon_threads = True
httpd.set_app(wsgi_handler)
httpd.serve_forever()
На рисунке ниже показаноWSGI ServerКлючевые классы и методы в потоке обработки сервера (из:ссылка_1)
1. WSGIServer
run()метод создастWSGIServerНапример, основной функцией является получение запросов от клиентов, передача запроса вWSGI Application,ПотомWSGI Applicationвозвращениеresponseвозвращен клиенту.
- При создании экземпляра указывается
HTTPпросилhandler:WSGIRequestHandlerсвоего рода; - пройти через
set_appиget_appУстановить метод и получитьWSGIApplicationпримерwsgi_handler; - иметь дело с
HTTPПо запросу звонитеhandler_requestметод, создастWSGIRequestHandlerобработка экземпляраHTTPпросить; -
WSGIServerсерединаget_requestметод переданsocketпринять данные запроса;
2. WSGIRequestHandler
- Зависит от
WSGIServerвызовhandle_requestПри создании экземпляра передатьrequest,cient_address,WSGIServerтри параметра,__init__Когда метод создается, он также вызывает свой собственныйhandleметод; -
handleметод создастServerHandlerэкземпляр, а затем вызвать егоrunспособ обработки запроса;
3. ServerHandler
-
WSGIRequestHandlerВ своемhandleвызов методаrunметод, пройтиself.server.get_app()параметры, получитьWSGIApplication, а затем вызовите экземпляр (call),Получатьresponse, который пройдет вstart_responseобратный вызов, используемый для обработки возвращенногоheaderиstatus; - пройти через
applicationПолучатьresponseпозже, черезfinish_responseвозвращениеresponse;
4. WSGIHandler (т.е. приложение Django WSGI)
-
WSGIв соглашенииapplication, получает два параметра,environСловарь содержит информацию, запрошенную клиентом, и другую информацию, которую можно рассматривать как контекст запроса,start_responseдля отправки обратноstatusиheaderфункция обратного вызова
Хотя тот, что вышеDjango WSGI ServerОн включает несколько реализаций классов и взаимные ссылки, но на самом деле принцип заключается в вызовеWSGIHandler, параметры входящего запроса и метод обратного вызоваstart_response()и вернуть ответ клиенту.
Python wsgiref simple_server
существуетPython3.7Исходный код даетsimple_serverДело находится вpython3.7/wsgiref/simple_server.py.
Модуль реализует простуюHTTPсервер и дает простойdemo, вы можете запустить его напрямую, и результат выполнения отобразит переменные среды, задействованные в запросе, в браузере. который включает в себя всюHTTPВсе компоненты запроса:ServerHandler,WSGIServer,WSGIRequestHandlerа такжеdemo_appупрощенный вариант представленияWSGIApplication.
Если вам интересно, вы можете сами взглянуть на исходный код.
загрузить конфигурацию
Djangoконфигурация находится в{project_name}/settings.pyопределяется в , может бытьDjangoКонфигурация также может быть пользовательской конфигурацией, и обеdjango.conf.settingsдоступ.
промежуточное ПО - промежуточное ПО
Обзор:
DjangoсерединаMiddlewareПодобно облегченной системе плагинов в нижнем слое, она может вмешиватьсяDjangoПроцесс запроса и ответа изменен глобальноDjangoвходное и выходное содержимое. Из общей схемы процесса видно, чтоDjangoСуть процесса обработки запроса заключается вMiddleware,DjangoВсе запросы и ответы вMiddlewareУчастие.
Подробности:
ОдинHTTPзапрос, который сначала преобразуется вHttpRequestобъект, который затем передаетсяRequest Middlewareобрабатывать, если он возвращаетсяHttpResponseобъект, он передается непосредственно вResponse MiddlewareСделайте последние штрихи. если неRequest MiddlewareпосетитURLнастраивать, ориентироватьсяviewиметь дело сHttpRequestобъект после определенияview, но если он не был выполнен, системаHttpRequestобъект переданView Middlewareобрабатывать, если он возвращаетсяHttpResponseобъект, тоHttpResponseобъект будет переданResponse Middlewareдля последующей обработки, иначе детерминированныйviewфункция процесса и возвратаHttpResponseобъект, если исключение выбрасывается и выбрасывается в течение всего процесса, оно будетException Middlewareдля обработки.
Порядок выполнения промежуточного ПО
На этапе запроса перед вызовом представленияDjangoв соответствии сsetting.pyПорядок настроек, выполнение обхода приложения сверху внизRequest Middleware. Вы можете думать об этом как о луковице: каждый класс промежуточного программного обеспечения представляет собой «слой», покрывающий ядро луковицы. Если запрос проходит через все слои луковицы (каждый вызовget_response), чтобы передать запрос на следующий уровень, вплоть до представления ядра, тогда ответ будет проходить через каждый уровень (в обратном порядке) на обратном пути.
Углубленный взгляд на то, как написать собственное промежуточное программное обеспечение, т.е. промежуточное программное обеспечение.
Легко написать собственное ПО промежуточного слоя, каждый компонент ПО промежуточного слоя является автономным.Python Class, вы можете настроитьClassНапишите один или несколько следующих методов:
process_request
Стиль функции:process_request(request);
Разбор параметров:requestЯвляетсяHTTPRequestобъект;
Время звонка: вкл.Djangoрешить, что выполнитьviewДо,process_request()будет вызван по запросу;
произвести ответ: он должен вернутьNoneилиHttpResponseобъект, если возвращаетсяNone,Djangoпродолжит обработку запроса; если он вернетHTTPResponseобъект,Djangoперейдет прямо кResponse Middleware;
process_view
Стиль функции:process_view(request, view_func, view_args, view_kwargs);
Разбор параметров:requestЯвляетсяHTTPRequestобъект,view_funcдаDjangoфункция, которая будет вызываться (точнее, объект функции, а не строка, представляющая имя функции),view_argsэто значение, которое будет передано в представление*args,view_kwargsэто значение, которое будет передано в представление**kwargs,view_argsиview_kwargsни включатьrequest;
Время звонка:process_view()Будет вDjangoперечислитьviewбыл вызван раньше;
произвести ответ: он должен вернутьNoneилиHttpResponseобъект, если возвращаетсяNone,Djangoпродолжит обработку запроса; если он вернетHTTPResponseобъект,Djangoперейдет прямо кResponse Middleware;
ПС: кромеCsrfViewMiddlewareВнешнее промежуточное ПО запускается перед запуском представления или вprocess_view()доступ вrequest.POSTсделает все последующие виды неизменяемымиrequest, поэтому его следует избегать, насколько это возможно.
process_template_response
Стиль функции:process_template_response(request, response);
Разбор параметров:requestЯвляетсяHttpRequestобъект,responseЯвляетсяTemplateResponseобъект (или аналогичный),DjangoView или промежуточное ПО возвращается;
Время звонка: еслиresponseПример этогоrender()метод,process_template_response()Вызывается сразу после выполнения представления, указывая, что этоTemplateResponseобъект (или аналогичный объект);
Генерировать ответ: этот метод должен возвращать реализацию, реализующуюrender()методTemplateResponseобъект (или аналогичный), который изменяет данныйresponseобъект или создать совершенно новыйTemplateResponseобъект (или аналогичный объект);
PS: на этапе обработки ответа промежуточное ПО выполняется в обратном порядке, включаяprocess_template_response;
process_response
Стиль функции:process_response(request, response);
Разбор параметров:requestЯвляетсяHttpRequestобъект,responseЯвляетсяHttpResponseобъект, поDjangoView или промежуточное ПО возвращается;
Время звонка:process_requestВызывается до того, как все ответы будут возвращены клиенту;
Создать ответ: этот метод должен возвращатьHttpRequestобъект, который изменяет данныйresponseобъект или создать совершенно новыйHttpRequestобъект;
PS:process_responseвсегда называется, что означает вашprocess_responseнельзя полагаться наprocess_request
process_exception
Стиль функции:process_exception(request, exception);
Разбор параметров:requestЯвляетсяHttpRequestобъект,exceptionбросается взглядомExceptionобъект;
Время вызова: когда представление выдает исключение,Djangoпозвонюprocess_exceptionобрабатывать;
произвести ответ: он должен вернутьNoneилиHttpResponseобъект, если возвращаетсяNone,Djangoпродолжит обработку запроса; если он вернетHTTPResponseобъект, объект шаблона иResponse Middlewareбудут возвращены непосредственно клиенту, в противном случае будет инициирована обработка исключений по умолчанию. ;
URL Resolver
Обзор:
Предположение: промежуточное ПО облегчает выполнение_request_middleware,_view_middlewareвернуться послеNone.
когдаDjangoобход завершен_request_middlewareзатем получит обработанныйrequestобъект, в настоящее времяDjangoбудет в паре по порядкуurlВыполнять обычное сопоставление, если совпадение не удалось, будет выдано исключение; если совпадение успешно,Djangoбудет продолжать цикл_view_middlewareИ продолжайте выполнять только что успешно совпавшие после выполненияview.
существуетsettingсуществует одинROOT_URLCONF, что указывает наurls.pyфайл, согласно которомуurlconf, по сути онurlи таблицу сопоставления между функциями представления, а затем передатьresolverРазобратьurl, найти первое соответствиеview.
Подробности:
Расположение исходного кода важной функции:
_path: django/urls/conf.py
URLPattern: django/urls/resolvers.py
ResolverMatch: django/urls/resolvers.py
URLResolver: django/urls/resolvers.py
Исходный код довольно длинный, поэтому я не буду его публиковать, если вам интересно, посмотрите сами.
- пройти через
urlpatternsвыполнение конфигурации_pathфункция; -
_pathфункция судить: если этоlistилиtuple, затем применитьURLResolverпроцесс, перейдите к 4; если обычный вызываемыйviewфункция, использованиеURLPatternОбработать, перейти к; если совпадение не удалось, выдать исключение; -
URLPatternВыполнить после инициализации соответствующего значенияresolveМетод: если совпадение прошло успешно, вернутьResolverMatch;если совпадение не удалось, генерировать исключение; -
URLResolverсовпадениеpathЕсли совпадение прошло успешно, продолжайте сопоставлять егоurl_patterns, перейти к 5, совпадение не удалось, выдать исключение; - совпадение
url_patterns: еслиurlpatternЕсли совпадение прошло успешно, вернитесьResolverMatch; еслиURLResolverрекурсивный вызовURLResolverПерейти к 4, если совпадение не удалось, создать исключение;
Можно обнаружить, что ключом ко всему процессу являетсяResolverMatch,URLPatternиURLResolverТри класса, из них:ResolverMatchрезультат сопоставления, который содержит информацию, необходимую после успешного сопоставления;URLPatternЯвляетсяurlОбъект картографической информации, содержащийurlСопоставьте соответствующие вызываемые объекты и другую информацию;URLResolverреализуетсяurlмаршрутизация, парсингurlключевое место этоurl_patternsлибоURLPatternтак же может бытьURLResolver, именно из-за этой конструкцииurlуровневый анализ.
Обзор
Реальный процесс запроса и ответа определенно сложнее, чем я упомянул, но мои способности действительно ограничены, и я могу понять только этот уровень в настоящее время.Если я ошибаюсь, пожалуйста, поправьте меня.
Использованная литература:
- Краткая книга: вам нужно понимать веб-разработку на Python: WSGI и uWSGI Автор: rainybowe
- Самородки: процесс Django от запроса до ответа
- Академия современной магии: Python и Django - Анализ процесса архитектуры Django
- Краткая книга: маршрутизация URL (URLResolver) для анализа исходного кода django Автор: 2hanson
- Официальная документация Джанго