используется в этой статье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
объект (или аналогичный),Django
View или промежуточное ПО возвращается;
Время звонка: еслиresponse
Пример этогоrender()
метод,process_template_response()
Вызывается сразу после выполнения представления, указывая, что этоTemplateResponse
объект (или аналогичный объект);
Генерировать ответ: этот метод должен возвращать реализацию, реализующуюrender()
методTemplateResponse
объект (или аналогичный), который изменяет данныйresponse
объект или создать совершенно новыйTemplateResponse
объект (или аналогичный объект);
PS: на этапе обработки ответа промежуточное ПО выполняется в обратном порядке, включаяprocess_template_response
;
process_response
Стиль функции:process_response(request, response)
;
Разбор параметров:request
ЯвляетсяHttpRequest
объект,response
ЯвляетсяHttpResponse
объект, поDjango
View или промежуточное ПО возвращается;
Время звонка: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
- Официальная документация Джанго