Browse Source
* Update Russian translations for modified pages * docs: fix translation for multiprocessing * Update Russian translations for other existing pages * Apply changes from latest PRs: 13917 and 14099 --------- Co-authored-by: vldmrdev <[email protected]>pull/14136/head
committed by
GitHub
74 changed files with 4117 additions and 3845 deletions
@ -1,3 +1,3 @@ |
|||
# О проекте |
|||
# О проекте { #about } |
|||
|
|||
FastAPI: внутреннее устройство, повлиявшие технологии и всё такое прочее. 🤓 |
|||
О FastAPI, его дизайне, источниках вдохновения и многом другом. 🤓 |
|||
|
@ -1,37 +1,34 @@ |
|||
# Замеры производительности |
|||
# Бенчмарки (тесты производительности) { #benchmarks } |
|||
|
|||
Независимые тесты производительности приложений от TechEmpower показывают, что **FastAPI** под управлением Uvicorn <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">один из самых быстрых Python-фреймворков</a> и уступает только Starlette и Uvicorn (которые используются в FastAPI). (*) |
|||
Независимые бенчмарки TechEmpower показывают, что приложения **FastAPI** под управлением Uvicorn — <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">одни из самых быстрых Python‑фреймворков</a>, уступающие только Starlette и самому Uvicorn (используются внутри FastAPI). |
|||
|
|||
Но при просмотре и сравнении замеров производительности следует иметь в виду нижеописанное. |
|||
Но при просмотре бенчмарков и сравнений следует иметь в виду следующее. |
|||
|
|||
## Замеры производительности и скорости |
|||
## Бенчмарки и скорость { #benchmarks-and-speed } |
|||
|
|||
В подобных тестах часто можно увидеть, что инструменты разного типа сравнивают друг с другом, как аналогичные. |
|||
При проверке бенчмарков часто можно увидеть, что инструменты разных типов сравнивают как эквивалентные. |
|||
|
|||
В частности, сравнивают вместе Uvicorn, Starlette и FastAPI (среди многих других инструментов). |
|||
В частности, часто сравнивают вместе Uvicorn, Starlette и FastAPI (среди многих других инструментов). |
|||
|
|||
Чем проще проблема, которую решает инструмент, тем выше его производительность. И большинство тестов не проверяют дополнительные функции, предоставляемые инструментом. |
|||
Чем проще задача, которую решает инструмент, тем выше его производительность. И большинство бенчмарков не тестируют дополнительные возможности, предоставляемые инструментом. |
|||
|
|||
Иерархия инструментов имеет следующий вид: |
|||
Иерархия выглядит так: |
|||
|
|||
* **Uvicorn**: ASGI-сервер |
|||
* **Starlette** (использует Uvicorn): веб-микрофреймворк |
|||
* **FastAPI** (использует Starlette): API-микрофреймворк с дополнительными функциями для создания API, с валидацией данных и т.д. |
|||
* **Starlette**: (использует Uvicorn) веб-микрофреймворк |
|||
* **FastAPI**: (использует Starlette) API-микрофреймворк с рядом дополнительных возможностей для создания API, включая валидацию данных и т. п. |
|||
|
|||
* **Uvicorn**: |
|||
* Будет иметь наилучшую производительность, так как не имеет большого количества дополнительного кода, кроме самого сервера. |
|||
* Вы не будете писать приложение на Uvicorn напрямую. Это означало бы, что Ваш код должен включать как минимум весь |
|||
код, предоставляемый Starlette (или **FastAPI**). И если Вы так сделаете, то в конечном итоге Ваше приложение будет иметь те же накладные расходы, что и при использовании фреймворка, минимизирующего код Вашего приложения и Ваши ошибки. |
|||
* Uvicorn подлежит сравнению с Daphne, Hypercorn, uWSGI и другими веб-серверами. |
|||
|
|||
* Будет иметь наилучшую производительность, так как помимо самого сервера у него немного дополнительного кода. |
|||
* Вы не будете писать приложение непосредственно на Uvicorn. Это означало бы, что Ваш код должен включать как минимум весь код, предоставляемый Starlette (или **FastAPI**). И если Вы так сделаете, то в конечном итоге Ваше приложение будет иметь те же накладные расходы, что и при использовании фреймворка, минимизирующего код Вашего приложения и Ваши ошибки. |
|||
* Если Вы сравниваете Uvicorn, сравнивайте его с Daphne, Hypercorn, uWSGI и т. д. — серверами приложений. |
|||
* **Starlette**: |
|||
* Будет уступать Uvicorn по производительности. Фактически Starlette управляется Uvicorn и из-за выполнения большего количества кода он не может быть быстрее, чем Uvicorn. |
|||
* Зато он предоставляет Вам инструменты для создания простых веб-приложений с обработкой маршрутов URL и т.д. |
|||
* Starlette следует сравнивать с Sanic, Flask, Django и другими веб-фреймворками (или микрофреймворками). |
|||
|
|||
* Будет на следующем месте по производительности после Uvicorn. Фактически Starlette запускается под управлением Uvicorn, поэтому он может быть только «медленнее» Uvicorn из‑за выполнения большего объёма кода. |
|||
* Зато он предоставляет Вам инструменты для создания простых веб‑приложений с маршрутизацией по путям и т. п. |
|||
* Если Вы сравниваете Starlette, сравнивайте его с Sanic, Flask, Django и т. д. — веб‑фреймворками (или микрофреймворками). |
|||
* **FastAPI**: |
|||
* Так же как Starlette использует Uvicorn и не может быть быстрее него, **FastAPI** использует Starlette, то есть он не может быть быстрее Starlette. |
|||
* FastAPI предоставляет больше возможностей поверх Starlette, которые наверняка Вам понадобятся при создании API, такие как проверка данных и сериализация. В довесок Вы ещё и получаете автоматическую документацию (автоматическая документация даже не увеличивает накладные расходы при работе приложения, так как она создается при запуске). |
|||
* Если Вы не используете FastAPI, а используете Starlette напрямую (или другой инструмент вроде Sanic, Flask, Responder и т.д.), Вам пришлось бы самостоятельно реализовать валидацию и сериализацию данных. То есть, в итоге, Ваше приложение имело бы такие же накладные расходы, как если бы оно было создано с использованием FastAPI. И во многих случаях валидация и сериализация данных представляют собой самый большой объём кода, написанного в приложениях. |
|||
* Таким образом, используя FastAPI Вы потратите меньше времени на разработку, уменьшите количество ошибок, строк кода и, вероятно, получите ту же производительность (или лучше), как и если бы не использовали его (поскольку Вам пришлось бы реализовать все его возможности в своем коде). |
|||
* FastAPI должно сравнивать с фреймворками веб-приложений (или наборами инструментов), которые обеспечивают валидацию и сериализацию данных, а также предоставляют автоматическую документацию, такими как Flask-apispec, NestJS, Molten и им подобные. |
|||
* Точно так же, как Starlette использует Uvicorn и не может быть быстрее него, **FastAPI** использует Starlette, поэтому не может быть быстрее его. |
|||
* FastAPI предоставляет больше возможностей поверх Starlette — те, которые почти всегда нужны при создании API, такие как валидация и сериализация данных. В довесок Вы ещё и получаете автоматическую документацию (автоматическая документация даже не увеличивает накладные расходы при работе приложения, так как она создаётся при запуске). |
|||
* Если бы Вы не использовали FastAPI, а использовали Starlette напрямую (или другой инструмент вроде Sanic, Flask, Responder и т. д.), Вам пришлось бы самостоятельно реализовать валидацию и сериализацию данных. То есть, в итоге, Ваше приложение имело бы такие же накладные расходы, как если бы оно было создано с использованием FastAPI. И во многих случаях валидация и сериализация данных представляют собой самый большой объём кода, написанного в приложениях. |
|||
* Таким образом, используя FastAPI, Вы экономите время разработки, уменьшаете количество ошибок, строк кода и, вероятно, получите ту же производительность (или лучше), как и если бы не использовали его (поскольку Вам пришлось бы реализовать все его возможности в своём коде). |
|||
* Если Вы сравниваете FastAPI, сравнивайте его с фреймворком веб‑приложений (или набором инструментов), который обеспечивает валидацию данных, сериализацию и документацию, такими как Flask-apispec, NestJS, Molten и им подобные. Фреймворки с интегрированной автоматической валидацией данных, сериализацией и документацией. |
|||
|
@ -1,323 +1,321 @@ |
|||
# Концепции развёртывания |
|||
# Концепции развёртывания { #deployments-concepts } |
|||
|
|||
Существует несколько концепций, применяемых для развёртывания приложений **FastAPI**, равно как и для любых других типов веб-приложений, среди которых вы можете выбрать **наиболее подходящий** способ. |
|||
При развёртывании приложения **FastAPI** (и вообще любого веб‑API) есть несколько концепций, о которых стоит думать — с их помощью можно выбрать **наиболее подходящий** способ **развёртывания вашего приложения**. |
|||
|
|||
Самые важные из них: |
|||
Некоторые из важных концепций: |
|||
|
|||
* Использование более безопасного протокола HTTPS |
|||
* Настройки запуска приложения |
|||
* Перезагрузка приложения |
|||
* Запуск нескольких экземпляров приложения |
|||
* Управление памятью |
|||
* Использование перечисленных функций перед запуском приложения. |
|||
* Безопасность — HTTPS |
|||
* Запуск при старте |
|||
* Перезапуски |
|||
* Репликация (количество запущенных процессов) |
|||
* Память |
|||
* Предварительные шаги перед запуском |
|||
|
|||
Рассмотрим ниже влияние каждого из них на процесс **развёртывания**. |
|||
Посмотрим, как они влияют на **развёртывания**. |
|||
|
|||
Наша конечная цель - **обслуживать клиентов вашего API безопасно** и **бесперебойно**, с максимально эффективным использованием **вычислительных ресурсов** (например, удалённых серверов/виртуальных машин). 🚀 |
|||
В конечном итоге цель — **обслуживать клиентов вашего API** безопасно, **избегать перебоев** и максимально эффективно использовать **вычислительные ресурсы** (например, удалённые серверы/виртуальные машины). 🚀 |
|||
|
|||
Здесь я немного расскажу Вам об этих **концепциях** и надеюсь, что у вас сложится **интуитивное понимание**, какой способ выбрать при развертывании вашего API в различных окружениях, возможно, даже **ещё не существующих**. |
|||
Здесь я немного расскажу о этих **концепциях**, чтобы у вас появилась **интуиция**, как развёртывать ваш API в разных окружениях, возможно даже в **будущих**, которых ещё не существует. |
|||
|
|||
Ознакомившись с этими концепциями, вы сможете **оценить и выбрать** лучший способ развёртывании **Вашего API**. |
|||
Учитывая эти концепции, вы сможете **оценить и спроектировать** лучший способ развёртывания **своих API**. |
|||
|
|||
В последующих главах я предоставлю Вам **конкретные рецепты** развёртывания приложения FastAPI. |
|||
В следующих главах я дам более **конкретные рецепты** по развёртыванию приложений FastAPI. |
|||
|
|||
А сейчас давайте остановимся на важных **идеях этих концепций**. Эти идеи можно также применить и к другим типам веб-приложений. 💡 |
|||
А пока давайте разберём важные **идеи**. Эти концепции применимы и к другим типам веб‑API. 💡 |
|||
|
|||
## Использование более безопасного протокола HTTPS |
|||
## Безопасность — HTTPS { #security-https } |
|||
|
|||
В [предыдущей главе об HTTPS](https.md){.internal-link target=_blank} мы рассмотрели, как HTTPS обеспечивает шифрование для вашего API. |
|||
В [предыдущей главе про HTTPS](https.md){.internal-link target=_blank} мы разобрались, как HTTPS обеспечивает шифрование для вашего API. |
|||
|
|||
Также мы заметили, что обычно для работы с HTTPS вашему приложению нужен **дополнительный** компонент - **прокси-сервер завершения работы TLS**. |
|||
Также мы увидели, что HTTPS обычно обеспечивает компонент, **внешний** по отношению к серверу вашего приложения — **TLS Termination Proxy**. |
|||
|
|||
И если прокси-сервер не умеет сам **обновлять сертификаты HTTPS**, то нужен ещё один компонент для этого действия. |
|||
И должен быть компонент, отвечающий за **обновление HTTPS‑сертификатов** — это может быть тот же самый компонент или отдельный. |
|||
|
|||
### Примеры инструментов для работы с HTTPS |
|||
### Примеры инструментов для HTTPS { #example-tools-for-https } |
|||
|
|||
Вот некоторые инструменты, которые вы можете применять как прокси-серверы: |
|||
Некоторые инструменты, которые можно использовать как TLS Termination Proxy: |
|||
|
|||
* Traefik |
|||
* С автоматическим обновлением сертификатов ✨ |
|||
* Автоматически обновляет сертификаты ✨ |
|||
* Caddy |
|||
* С автоматическим обновлением сертификатов ✨ |
|||
* Автоматически обновляет сертификаты ✨ |
|||
* Nginx |
|||
* С дополнительным компонентом типа Certbot для обновления сертификатов |
|||
* С внешним компонентом (например, Certbot) для обновления сертификатов |
|||
* HAProxy |
|||
* С дополнительным компонентом типа Certbot для обновления сертификатов |
|||
* Kubernetes с Ingress Controller похожим на Nginx |
|||
* С дополнительным компонентом типа cert-manager для обновления сертификатов |
|||
* Использование услуг облачного провайдера (читайте ниже 👇) |
|||
* С внешним компонентом (например, Certbot) для обновления сертификатов |
|||
* Kubernetes с Ingress Controller (например, Nginx) |
|||
* С внешним компонентом (например, cert-manager) для обновления сертификатов |
|||
* Обрабатывается внутри облачного провайдера как часть его услуг (см. ниже 👇) |
|||
|
|||
В последнем варианте вы можете воспользоваться услугами **облачного сервиса**, который сделает большую часть работы, включая настройку HTTPS. Это может наложить дополнительные ограничения или потребовать дополнительную плату и т.п. Зато Вам не понадобится самостоятельно заниматься настройками прокси-сервера. |
|||
Другой вариант — использовать **облачный сервис**, который возьмёт на себя больше задач, включая настройку HTTPS. Там могут быть ограничения или дополнительная стоимость и т.п., но в таком случае вам не придётся самим настраивать TLS Termination Proxy. |
|||
|
|||
В дальнейшем я покажу Вам некоторые конкретные примеры их применения. |
|||
В следующих главах я покажу конкретные примеры. |
|||
|
|||
--- |
|||
|
|||
Следующие концепции рассматривают применение программы, запускающей Ваш API (такой как Uvicorn). |
|||
Далее рассмотрим концепции, связанные с программой, которая запускает ваш реальный API (например, Uvicorn). |
|||
|
|||
## Программа и процесс |
|||
## Программа и процесс { #program-and-process } |
|||
|
|||
Мы часто будем встречать слова **процесс** и **программа**, потому следует уяснить отличия между ними. |
|||
Мы часто будем говорить о работающем "**процессе**", поэтому полезно чётко понимать, что это значит и чем отличается от "**программы**". |
|||
|
|||
### Что такое программа |
|||
### Что такое программа { #what-is-a-program } |
|||
|
|||
Термином **программа** обычно описывают множество вещей: |
|||
Словом **программа** обычно называют разные вещи: |
|||
|
|||
* **Код**, который вы написали, в нашем случае **Python-файлы**. |
|||
* **Файл**, который может быть **исполнен** операционной системой, например `python`, `python.exe` или `uvicorn`. |
|||
* Конкретная программа, **запущенная** операционной системой и использующая центральный процессор и память. В таком случае это также называется **процесс**. |
|||
* **Код**, который вы пишете, то есть **Python‑файлы**. |
|||
* **Файл**, который может быть **запущен** операционной системой, например: `python`, `python.exe` или `uvicorn`. |
|||
* Конкретную программу в момент, когда она **работает** в операционной системе, используя CPU и память. Это также называют **процессом**. |
|||
|
|||
### Что такое процесс |
|||
### Что такое процесс { #what-is-a-process } |
|||
|
|||
Термин **процесс** имеет более узкое толкование, подразумевая что-то, запущенное операционной системой (как в последнем пункте из вышестоящего абзаца): |
|||
Слово **процесс** обычно используют более конкретно — только для того, что реально выполняется в операционной системе (как в последнем пункте выше): |
|||
|
|||
* Конкретная программа, **запущенная** операционной системой. |
|||
* Это не имеет отношения к какому-либо файлу или коду, но нечто **определённое**, управляемое и **выполняемое** операционной системой. |
|||
* Любая программа, любой код, **могут делать что-то** только когда они **выполняются**. То есть, когда являются **работающим процессом**. |
|||
* Процесс может быть **прерван** (или "убит") Вами или вашей операционной системой. В результате чего он перестанет исполняться и **не будет продолжать делать что-либо**. |
|||
* Каждое приложение, которое вы запустили на своём компьютере, каждая программа, каждое "окно" запускает какой-то процесс. И обычно на включенном компьютере **одновременно** запущено множество процессов. |
|||
* И **одна программа** может запустить **несколько параллельных процессов**. |
|||
* Конкретная программа в момент, когда она **запущена** в операционной системе. |
|||
* Речь не о файле и не о коде, а **конкретно** о том, что **исполняется** и управляется операционной системой. |
|||
* Любая программа, любой код **могут что‑то делать** только когда **исполняются**, то есть когда есть **работающий процесс**. |
|||
* Процесс можно **завершить** (или «убить») вами или операционной системой. В этот момент он перестаёт выполняться и **больше ничего делать не может**. |
|||
* У каждого запущенного приложения на вашем компьютере есть свой процесс; у каждой программы, у каждого окна и т.д. Обычно одновременно **работает много процессов**, пока компьютер включён. |
|||
* Могут **одновременно** работать **несколько процессов** одной и той же **программы**. |
|||
|
|||
Если вы заглянете в "диспетчер задач" или "системный монитор" (или аналогичные инструменты) вашей операционной системы, то увидите множество работающих процессов. |
|||
Если вы посмотрите «диспетчер задач» или «системный монитор» (или аналогичные инструменты) в вашей операционной системе, то увидите множество работающих процессов. |
|||
|
|||
Вполне вероятно, что вы увидите несколько процессов с одним и тем же названием браузерной программы (Firefox, Chrome, Edge и т. Д.). Обычно браузеры запускают один процесс на вкладку и вдобавок некоторые дополнительные процессы. |
|||
Например, вы, скорее всего, увидите несколько процессов одного и того же браузера (Firefox, Chrome, Edge и т.д.). Обычно браузеры запускают один процесс на вкладку плюс дополнительные процессы. |
|||
|
|||
<img class="shadow" src="/img/deployment/concepts/image01.png"> |
|||
|
|||
--- |
|||
|
|||
Теперь, когда нам известна разница между **процессом** и **программой**, давайте продолжим обсуждение развёртывания. |
|||
Теперь, когда мы понимаем разницу между **процессом** и **программой**, продолжим разговор о развёртываниях. |
|||
|
|||
## Настройки запуска приложения |
|||
## Запуск при старте { #running-on-startup } |
|||
|
|||
В большинстве случаев когда вы создаёте веб-приложение, то желаете, чтоб оно **работало постоянно** и непрерывно, предоставляя клиентам доступ в любое время. Хотя иногда у вас могут быть причины, чтоб оно запускалось только при определённых условиях. |
|||
В большинстве случаев, создавая веб‑API, вы хотите, чтобы он **работал постоянно**, без перерывов, чтобы клиенты всегда могли к нему обратиться. Разве что у вас есть особые причины запускать его только при определённых условиях, но обычно вы хотите, чтобы он был постоянно запущен и **доступен**. |
|||
|
|||
### Удалённый сервер |
|||
### На удалённом сервере { #in-a-remote-server } |
|||
|
|||
Когда вы настраиваете удалённый сервер (облачный сервер, виртуальную машину и т.п.), самое простое, что можно сделать, запустить Uvicorn (или его аналог) вручную, как вы делаете при локальной разработке. |
|||
Когда вы настраиваете удалённый сервер (облачный сервер, виртуальную машину и т.п.), самый простой вариант — вручную использовать `fastapi run` (он использует Uvicorn) или что‑то похожее, как вы делаете при локальной разработке. |
|||
|
|||
Это рабочий способ и он полезен **во время разработки**. |
|||
Это будет работать и полезно **во время разработки**. |
|||
|
|||
Но если вы потеряете соединение с сервером, то не сможете отслеживать - работает ли всё ещё **запущенный Вами процесс**. |
|||
Но если соединение с сервером прервётся, **запущенный процесс**, скорее всего, завершится. |
|||
|
|||
И если сервер перезагрузится (например, после обновления или каких-то действий облачного провайдера), вы скорее всего **этого не заметите**, чтобы снова запустить процесс вручную. Вследствие этого Ваш API останется мёртвым. 😱 |
|||
А если сервер перезагрузится (например, после обновлений или миграций у облачного провайдера), вы, вероятно, **даже не заметите этого**. Из‑за этого вы не узнаете, что нужно вручную перезапустить процесс — и ваш API просто будет «мёртв». 😱 |
|||
|
|||
### Автоматический запуск программ |
|||
### Автоматический запуск при старте { #run-automatically-on-startup } |
|||
|
|||
Вероятно вы захотите, чтоб Ваша серверная программа (такая, как Uvicorn) стартовала автоматически при включении сервера, без **человеческого вмешательства** и всегда могла управлять Вашим API (так как Uvicorn запускает приложение FastAPI). |
|||
Как правило, вы захотите, чтобы серверная программа (например, Uvicorn) запускалась автоматически при старте сервера и без **участия человека**, чтобы всегда был процесс, запущенный с вашим API (например, Uvicorn, запускающий ваше приложение FastAPI). |
|||
|
|||
### Отдельная программа |
|||
### Отдельная программа { #separate-program } |
|||
|
|||
Для этого у обычно используют отдельную программу, которая следит за тем, чтобы Ваши приложения запускались при включении сервера. Такой подход гарантирует, что другие компоненты или приложения также будут запущены, например, база данных |
|||
Чтобы этого добиться, обычно используют **отдельную программу**, которая гарантирует запуск вашего приложения при старте. Во многих случаях она также запускает и другие компоненты/приложения, например базу данных. |
|||
|
|||
### Примеры инструментов, управляющих запуском программ |
|||
### Примеры инструментов для запуска при старте { #example-tools-to-run-at-startup } |
|||
|
|||
Вот несколько примеров, которые могут справиться с такой задачей: |
|||
Примеры инструментов, которые могут с этим справиться: |
|||
|
|||
* Docker |
|||
* Kubernetes |
|||
* Docker Compose |
|||
* Docker в режиме Swarm |
|||
* Docker в режиме Swarm (Swarm Mode) |
|||
* Systemd |
|||
* Supervisor |
|||
* Использование услуг облачного провайдера |
|||
* Обработка внутри облачного провайдера как часть его услуг |
|||
* Прочие... |
|||
|
|||
Я покажу Вам некоторые примеры их использования в следующих главах. |
|||
Более конкретные примеры будут в следующих главах. |
|||
|
|||
## Перезапуск |
|||
## Перезапуски { #restarts } |
|||
|
|||
Вы, вероятно, также захотите, чтоб ваше приложение **перезапускалось**, если в нём произошёл сбой. |
|||
Подобно тому как вы обеспечиваете запуск приложения при старте, вы, вероятно, захотите обеспечить его **перезапуск** после сбоев. |
|||
|
|||
### Мы ошибаемся |
|||
### Мы ошибаемся { #we-make-mistakes } |
|||
|
|||
Все люди совершают **ошибки**. Программное обеспечение почти *всегда* содержит **баги** спрятавшиеся в разных местах. 🐛 |
|||
Мы, люди, постоянно совершаем **ошибки**. В программном обеспечении почти всегда есть **баги**, скрытые в разных местах. 🐛 |
|||
|
|||
И мы, будучи разработчиками, продолжаем улучшать код, когда обнаруживаем в нём баги или добавляем новый функционал (возможно, добавляя при этом баги 😅). |
|||
И мы, как разработчики, продолжаем улучшать код — находим баги и добавляем новые возможности (иногда добавляя новые баги 😅). |
|||
|
|||
### Небольшие ошибки обрабатываются автоматически |
|||
### Небольшие ошибки обрабатываются автоматически { #small-errors-automatically-handled } |
|||
|
|||
Когда вы создаёте свои API на основе FastAPI и допускаете в коде ошибку, то FastAPI обычно остановит её распространение внутри одного запроса, при обработке которого она возникла. 🛡 |
|||
Создавая веб‑API с FastAPI, если в нашем коде возникает ошибка, FastAPI обычно «локализует» её в пределах одного запроса, который эту ошибку вызвал. 🛡 |
|||
|
|||
Клиент получит ошибку **500 Internal Server Error** в ответ на свой запрос, но приложение не сломается и будет продолжать работать с последующими запросами. |
|||
Клиент получит **500 Internal Server Error** для этого запроса, но приложение продолжит работать для последующих запросов, а не «упадёт» целиком. |
|||
|
|||
### Большие ошибки - Падение приложений |
|||
### Большие ошибки — падения { #bigger-errors-crashes } |
|||
|
|||
Тем не менее, может случиться так, что ошибка вызовет **сбой всего приложения** или даже сбой в Uvicorn, а то и в самом Python. 💥 |
|||
Тем не менее возможны случаи, когда код **роняет всё приложение**, приводя к сбою Uvicorn и Python. 💥 |
|||
|
|||
Но мы всё ещё хотим, чтобы приложение **продолжало работать** несмотря на эту единственную ошибку, обрабатывая, как минимум, запросы к *операциям пути* не имеющим ошибок. |
|||
И вы, скорее всего, не захотите, чтобы приложение оставалось «мёртвым» из‑за ошибки в одном месте — вы захотите, чтобы оно **продолжало работать** хотя бы для *операций пути*, которые не сломаны. |
|||
|
|||
### Перезапуск после падения |
|||
### Перезапуск после падения { #restart-after-crash } |
|||
|
|||
Для случаев, когда ошибки приводят к сбою в запущенном **процессе**, Вам понадобится добавить компонент, который **перезапустит** процесс хотя бы пару раз... |
|||
В случаях действительно серьёзных ошибок, которые роняют работающий **процесс**, вам понадобится внешний компонент, отвечающий за **перезапуск** процесса, как минимум пару раз... |
|||
|
|||
/// tip | Заметка |
|||
/// tip | Совет |
|||
|
|||
... Если приложение падает сразу же после запуска, вероятно бесполезно его бесконечно перезапускать. Но полагаю, вы заметите такое поведение во время разработки или, по крайней мере, сразу после развёртывания. |
|||
...Хотя если приложение **падает сразу же**, вероятно, нет смысла перезапускать его бесконечно. Но такие случаи вы, скорее всего, заметите во время разработки или как минимум сразу после развёртывания. |
|||
|
|||
Так что давайте сосредоточимся на конкретных случаях, когда приложение может полностью выйти из строя, но всё ещё есть смысл его запустить заново. |
|||
Давайте сосредоточимся на основных сценариях, когда в каких‑то конкретных ситуациях **в будущем** приложение может падать целиком, и при этом имеет смысл его перезапускать. |
|||
|
|||
/// |
|||
|
|||
Возможно вы захотите, чтоб был некий **внешний компонент**, ответственный за перезапуск вашего приложения даже если уже не работает Uvicorn или Python. То есть ничего из того, что написано в вашем коде внутри приложения, не может быть выполнено в принципе. |
|||
Скорее всего, вы захотите, чтобы перезапуском вашего приложения занимался **внешний компонент**, потому что к тому моменту Uvicorn и Python уже упали, и внутри того же кода вашего приложения сделать уже ничего нельзя. |
|||
|
|||
### Примеры инструментов для автоматического перезапуска |
|||
### Примеры инструментов для автоматического перезапуска { #example-tools-to-restart-automatically } |
|||
|
|||
В большинстве случаев инструменты **запускающие программы при старте сервера** умеют **перезапускать** эти программы. |
|||
В большинстве случаев тот же инструмент, который **запускает программу при старте**, умеет обрабатывать и автоматические **перезапуски**. |
|||
|
|||
В качестве примера можно взять те же: |
|||
Например, это может быть: |
|||
|
|||
* Docker |
|||
* Kubernetes |
|||
* Docker Compose |
|||
* Docker в режиме Swarm |
|||
* Docker в режиме Swarm (Swarm Mode) |
|||
* Systemd |
|||
* Supervisor |
|||
* Использование услуг облачного провайдера |
|||
* Обработка внутри облачного провайдера как часть его услуг |
|||
* Прочие... |
|||
|
|||
## Запуск нескольких экземпляров приложения (Репликация) - Процессы и память |
|||
## Репликация — процессы и память { #replication-processes-and-memory } |
|||
|
|||
Приложение FastAPI, управляемое серверной программой (такой как Uvicorn), запускается как **один процесс** и может обслуживать множество клиентов одновременно. |
|||
В приложении FastAPI, используя серверную программу (например, команду `fastapi`, которая запускает Uvicorn), запуск в **одном процессе** уже позволяет обслуживать нескольких клиентов одновременно. |
|||
|
|||
Но часто Вам может понадобиться несколько одновременно работающих одинаковых процессов. |
|||
Но во многих случаях вы захотите одновременно запустить несколько процессов‑воркеров. |
|||
|
|||
### Множество процессов - Воркеры (Workers) |
|||
### Несколько процессов — Воркеры { #multiple-processes-workers } |
|||
|
|||
Если количество Ваших клиентов больше, чем может обслужить один процесс (допустим, что виртуальная машина не слишком мощная), но при этом Вам доступно **несколько ядер процессора**, то вы можете запустить **несколько процессов** одного и того же приложения параллельно и распределить запросы между этими процессами. |
|||
Если клиентов больше, чем способен обслужить один процесс (например, если виртуальная машина не слишком мощная), и на сервере есть **несколько ядер CPU**, вы можете запустить **несколько процессов** одного и того же приложения параллельно и распределять запросы между ними. |
|||
|
|||
**Несколько запущенных процессов** одной и той же API-программы часто называют **воркерами**. |
|||
Когда вы запускаете **несколько процессов** одной и той же программы API, их обычно называют **воркерами**. |
|||
|
|||
### Процессы и порты́ |
|||
### Процессы‑воркеры и порты { #worker-processes-and-ports } |
|||
|
|||
Помните ли Вы, как на странице [Об HTTPS](https.md){.internal-link target=_blank} мы обсуждали, что на сервере только один процесс может слушать одну комбинацию IP-адреса и порта? |
|||
Помните из раздела [Об HTTPS](https.md){.internal-link target=_blank}, что на сервере только один процесс может слушать конкретную комбинацию порта и IP‑адреса? |
|||
|
|||
С тех пор ничего не изменилось. |
|||
Это по‑прежнему так. |
|||
|
|||
Соответственно, чтобы иметь возможность работать с **несколькими процессами** одновременно, должен быть **один процесс, прослушивающий порт** и затем каким-либо образом передающий данные каждому рабочему процессу. |
|||
Поэтому, чтобы одновременно работало **несколько процессов**, должен быть **один процесс, слушающий порт**, который затем каким‑то образом передаёт коммуникацию каждому воркер‑процессу. |
|||
|
|||
### У каждого процесса своя память |
|||
### Память на процесс { #memory-per-process } |
|||
|
|||
Работающая программа загружает в память данные, необходимые для её работы, например, переменные содержащие модели машинного обучения или большие файлы. Каждая переменная **потребляет некоторое количество оперативной памяти (RAM)** сервера. |
|||
Когда программа загружает что‑то в память (например, модель машинного обучения в переменную или содержимое большого файла в переменную), всё это **потребляет часть памяти (RAM)** сервера. |
|||
|
|||
Обычно процессы **не делятся памятью друг с другом**. Сие означает, что каждый работающий процесс имеет свои данные, переменные и свой кусок памяти. И если для выполнения вашего кода процессу нужно много памяти, то **каждый такой же процесс** запущенный дополнительно, потребует такого же количества памяти. |
|||
И разные процессы обычно **не делят память**. Это значит, что у каждого процесса свои переменные и своя память. Если ваш код потребляет много памяти, то **каждый процесс** будет потреблять сопоставимый объём памяти. |
|||
|
|||
### Память сервера |
|||
### Память сервера { #server-memory } |
|||
|
|||
Допустим, что Ваш код загружает модель машинного обучения **размером 1 ГБ**. Когда вы запустите своё API как один процесс, он займёт в оперативной памяти не менее 1 ГБ. А если вы запустите **4 таких же процесса** (4 воркера), то каждый из них займёт 1 ГБ оперативной памяти. В результате вашему API потребуется **4 ГБ оперативной памяти (RAM)**. |
|||
Например, если ваш код загружает модель Машинного обучения размером **1 ГБ**, то при запуске одного процесса с вашим API он будет использовать как минимум 1 ГБ RAM. А если вы запустите **4 процесса** (4 воркера), каждый процесс будет использовать 1 ГБ RAM. Всего ваш API будет потреблять **4 ГБ RAM**. |
|||
|
|||
И если Ваш удалённый сервер или виртуальная машина располагает только 3 ГБ памяти, то попытка загрузить в неё 4 ГБ данных вызовет проблемы. 🚨 |
|||
И если у вашего удалённого сервера или виртуальной машины только 3 ГБ RAM, попытка загрузить более 4 ГБ вызовет проблемы. 🚨 |
|||
|
|||
### Множество процессов - Пример |
|||
### Несколько процессов — пример { #multiple-processes-an-example } |
|||
|
|||
В этом примере **менеджер процессов** запустит и будет управлять двумя **воркерами**. |
|||
В этом примере есть **процесс‑менеджер**, который запускает и контролирует два **процесса‑воркера**. |
|||
|
|||
Менеджер процессов будет слушать определённый **сокет** (IP:порт) и передавать данные работающим процессам. |
|||
Процесс‑менеджер, вероятно, будет тем, кто слушает **порт** на IP. И он будет передавать всю коммуникацию воркер‑процессам. |
|||
|
|||
Каждый из этих процессов будет запускать ваше приложение для обработки полученного **запроса** и возвращения вычисленного **ответа** и они будут использовать оперативную память. |
|||
Эти воркеры будут запускать ваше приложение, выполнять основные вычисления для получения **запроса** и возврата **ответа**, и загружать всё, что вы кладёте в переменные, в RAM. |
|||
|
|||
<img src="/img/deployment/concepts/process-ram.drawio.svg"> |
|||
|
|||
Безусловно, на этом же сервере будут работать и **другие процессы**, которые не относятся к вашему приложению. |
|||
Конечно, на той же машине помимо вашего приложения, скорее всего, будут работать и **другие процессы**. |
|||
|
|||
Интересная деталь заключается в том, что процент **использования центрального процессора (CPU)** каждым процессом может сильно меняться с течением времени, но объём занимаемой **оперативной памяти (RAM)** остаётся относительно **стабильным**. |
|||
Интересная деталь: процент **использования CPU** каждым процессом со временем может сильно **меняться**, но **память (RAM)** обычно остаётся более‑менее **стабильной**. |
|||
|
|||
Если у вас есть API, который каждый раз выполняет сопоставимый объем вычислений, и у вас много клиентов, то **загрузка процессора**, вероятно, *также будет стабильной* (вместо того, чтобы постоянно быстро увеличиваться и уменьшаться). |
|||
Если у вас API, который каждый раз выполняет сопоставимый объём вычислений, и у вас много клиентов, то **загрузка процессора**, вероятно, *тоже будет стабильной* (вместо того, чтобы быстро и постоянно «скакать»). |
|||
|
|||
### Примеры стратегий и инструментов для запуска нескольких экземпляров приложения |
|||
### Примеры инструментов и стратегий репликации { #examples-of-replication-tools-and-strategies } |
|||
|
|||
Существует несколько подходов для достижения целей репликации и я расскажу Вам больше о конкретных стратегиях в следующих главах, например, когда речь пойдет о Docker и контейнерах. |
|||
Есть несколько подходов для достижения этого, и я расскажу больше о конкретных стратегиях в следующих главах, например, говоря о Docker и контейнерах. |
|||
|
|||
Основное ограничение при этом - только **один** компонент может работать с определённым **портом публичного IP**. И должен быть способ **передачи** данных между этим компонентом и копиями **процессов/воркеров**. |
|||
Главное ограничение: должен быть **один** компонент, который обрабатывает **порт** на **публичном IP**. И у него должен быть способ **передавать** коммуникацию реплицированным **процессам/воркерам**. |
|||
|
|||
Вот некоторые возможные комбинации и стратегии: |
|||
Некоторые возможные комбинации и стратегии: |
|||
|
|||
* **Gunicorn** управляющий **воркерами Uvicorn** |
|||
* Gunicorn будет выступать как **менеджер процессов**, прослушивая **IP:port**. Необходимое количество запущенных экземпляров приложения будет осуществляться посредством запуска **множества работающих процессов Uvicorn**. |
|||
* **Uvicorn** управляющий **воркерами Uvicorn** |
|||
* Один процесс Uvicorn будет выступать как **менеджер процессов**, прослушивая **IP:port**. Он будет запускать **множество работающих процессов Uvicorn**. |
|||
* **Kubernetes** и аналогичные **контейнерные системы** |
|||
* Какой-то компонент в **Kubernetes** будет слушать **IP:port**. Необходимое количество запущенных экземпляров приложения будет осуществляться посредством запуска **нескольких контейнеров**, в каждом из которых работает **один процесс Uvicorn**. |
|||
* **Облачные сервисы**, которые позаботятся обо всём за Вас |
|||
* Возможно, что облачный сервис умеет **управлять запуском дополнительных экземпляров приложения**. Вероятно, он потребует, чтоб вы указали - какой **процесс** или **образ** следует клонировать. Скорее всего, вы укажете **один процесс Uvicorn** и облачный сервис будет запускать его копии при необходимости. |
|||
* **Uvicorn** с `--workers` |
|||
* Один **процесс‑менеджер** Uvicorn будет слушать **IP** и **порт** и запускать **несколько процессов‑воркеров Uvicorn**. |
|||
* **Kubernetes** и другие распределённые **контейнерные системы** |
|||
* Некий компонент на уровне **Kubernetes** будет слушать **IP** и **порт**. Репликация достигается с помощью **нескольких контейнеров**, в каждом из которых работает **один процесс Uvicorn**. |
|||
* **Облачные сервисы**, которые берут это на себя |
|||
* Облачный сервис, скорее всего, **возьмёт репликацию на себя**. Он, возможно, позволит указать **процесс для запуска** или **образ контейнера**. В любом случае это, скорее всего, будет **один процесс Uvicorn**, а сервис займётся его репликацией. |
|||
|
|||
/// tip | Заметка |
|||
/// tip | Совет |
|||
|
|||
Если вы не знаете, что такое **контейнеры**, Docker или Kubernetes, не переживайте. |
|||
Не беспокойтесь, если некоторые пункты про **контейнеры**, Docker или Kubernetes пока кажутся неочевидными. |
|||
|
|||
Я поведаю Вам о контейнерах, образах, Docker, Kubernetes и т.п. в главе: [FastAPI внутри контейнеров - Docker](docker.md){.internal-link target=_blank}. |
|||
Я расскажу больше про образы контейнеров, Docker, Kubernetes и т.п. в следующей главе: [FastAPI внутри контейнеров — Docker](docker.md){.internal-link target=_blank}. |
|||
|
|||
/// |
|||
|
|||
## Шаги, предшествующие запуску |
|||
## Предварительные шаги перед запуском { #previous-steps-before-starting } |
|||
|
|||
Часто бывает, что Вам необходимо произвести какие-то подготовительные шаги **перед запуском** своего приложения. |
|||
Во многих случаях вы захотите выполнить некоторые шаги **перед запуском** приложения. |
|||
|
|||
Например, запустить **миграции базы данных**. |
|||
|
|||
Но в большинстве случаев такие действия достаточно произвести **однократно**. |
|||
Но чаще всего эти шаги нужно выполнять только **один раз**. |
|||
|
|||
Поэтому Вам нужен будет **один процесс**, выполняющий эти **подготовительные шаги** до запуска приложения. |
|||
Поэтому вы захотите иметь **один процесс**, который выполнит эти **предварительные шаги**, прежде чем запускать приложение. |
|||
|
|||
Также Вам нужно будет убедиться, что этот процесс выполнил подготовительные шаги *даже* если впоследствии вы запустите **несколько процессов** (несколько воркеров) самого приложения. Если бы эти шаги выполнялись в каждом **клонированном процессе**, они бы **дублировали** работу, пытаясь выполнить её **параллельно**. И если бы эта работа была бы чем-то деликатным, вроде миграции базы данных, то это может вызвать конфликты между ними. |
|||
И вам нужно будет убедиться, что это делает один процесс **даже** если потом вы запускаете **несколько процессов** (несколько воркеров) самого приложения. Если эти шаги выполнят **несколько процессов**, они **дублируют** работу, запустив её **параллельно**, и, если речь о чём‑то деликатном (например, миграции БД), это может вызвать конфликты. |
|||
|
|||
Безусловно, возможны случаи, когда нет проблем при выполнении предварительной подготовки параллельно или несколько раз. Тогда Вам повезло, работать с ними намного проще. |
|||
Конечно, бывают случаи, когда нет проблем, если предварительные шаги выполняются несколько раз — тогда всё проще. |
|||
|
|||
/// tip | Заметка |
|||
/// tip | Совет |
|||
|
|||
Имейте в виду, что в некоторых случаях запуск вашего приложения **может не требовать каких-либо предварительных шагов вовсе**. |
|||
Также учтите, что в зависимости от вашей схемы развёртывания в некоторых случаях **предварительные шаги могут вовсе не требоваться**. |
|||
|
|||
Что ж, тогда Вам не нужно беспокоиться об этом. 🤷 |
|||
Тогда об этом можно не беспокоиться. 🤷 |
|||
|
|||
/// |
|||
|
|||
### Примеры стратегий запуска предварительных шагов |
|||
### Примеры стратегий для предварительных шагов { #examples-of-previous-steps-strategies } |
|||
|
|||
Существует **сильная зависимость** от того, как вы **развёртываете свою систему**, запускаете программы, обрабатываете перезапуски и т.д. |
|||
Это будет **сильно зависеть** от того, как вы **развёртываете систему**, как запускаете программы, обрабатываете перезапуски и т.д. |
|||
|
|||
Вот некоторые возможные идеи: |
|||
Некоторые возможные идеи: |
|||
|
|||
* При использовании Kubernetes нужно предусмотреть "инициализирующий контейнер", запускаемый до контейнера с приложением. |
|||
* Bash-скрипт, выполняющий предварительные шаги, а затем запускающий приложение. |
|||
* При этом Вам всё ещё нужно найти способ - как запускать/перезапускать *такой* bash-скрипт, обнаруживать ошибки и т.п. |
|||
* «Init Container» в Kubernetes, который запускается перед контейнером с приложением |
|||
* Bash‑скрипт, который выполняет предварительные шаги, а затем запускает приложение |
|||
* При этом всё равно нужен способ запускать/перезапускать *этот* bash‑скрипт, обнаруживать ошибки и т.п. |
|||
|
|||
/// tip | Заметка |
|||
/// tip | Совет |
|||
|
|||
Я приведу Вам больше конкретных примеров работы с контейнерами в главе: [FastAPI внутри контейнеров - Docker](docker.md){.internal-link target=_blank}. |
|||
Я приведу более конкретные примеры с контейнерами в следующей главе: [FastAPI внутри контейнеров — Docker](docker.md){.internal-link target=_blank}. |
|||
|
|||
/// |
|||
|
|||
## Утилизация ресурсов |
|||
## Использование ресурсов { #resource-utilization } |
|||
|
|||
Ваш сервер располагает ресурсами, которые Ваши программы могут потреблять или **утилизировать**, а именно - время работы центрального процессора и объём оперативной памяти. |
|||
Ваш сервер(а) — это **ресурс**, который ваши программы могут потреблять или **использовать**: время вычислений на CPU и доступную оперативную память (RAM). |
|||
|
|||
Как много системных ресурсов вы предполагаете потребить/утилизировать? Если не задумываться, то можно ответить - "немного", но на самом деле Вы, вероятно, захотите использовать **максимально возможное количество**. |
|||
Какую долю системных ресурсов вы хотите потреблять/использовать? Можно подумать «немного», но на практике вы, скорее всего, захотите потреблять **максимум без падений**. |
|||
|
|||
Если вы платите за содержание трёх серверов, но используете лишь малую часть системных ресурсов каждого из них, то вы **выбрасываете деньги на ветер**, а также **впустую тратите электроэнергию** и т.п. |
|||
Если вы платите за 3 сервера, но используете лишь малую часть их RAM и CPU, вы, вероятно, **тратите деньги впустую** 💸 и **электроэнергию серверов** 🌎 и т.п. |
|||
|
|||
В таком случае было бы лучше обойтись двумя серверами, но более полно утилизировать их ресурсы (центральный процессор, оперативную память, жёсткий диск, сети передачи данных и т.д). |
|||
В таком случае лучше иметь 2 сервера и использовать более высокий процент их ресурсов (CPU, память, диск, сетевую полосу и т.д.). |
|||
|
|||
С другой стороны, если вы располагаете только двумя серверами и используете **на 100% их процессоры и память**, но какой-либо процесс запросит дополнительную память, то операционная система сервера будет использовать жёсткий диск для расширения оперативной памяти (а диск работает в тысячи раз медленнее), а то вовсе **упадёт**. Или если какому-то процессу понадобится произвести вычисления, то ему придётся подождать, пока процессор освободится. |
|||
С другой стороны, если у вас 2 сервера и вы используете **100% их CPU и RAM**, в какой‑то момент один процесс попросит больше памяти, и сервер начнёт использовать диск как «память» (что в тысячи раз медленнее) или даже **упадёт**. Или процессу понадобятся вычисления, но ему придётся ждать освобождения CPU. |
|||
|
|||
В такой ситуации лучше подключить **ещё один сервер** и перераспределить процессы между серверами, чтоб всем **хватало памяти и процессорного времени**. |
|||
В таком случае лучше добавить **ещё один сервер** и запустить часть процессов на нём, чтобы у всех было **достаточно RAM и времени CPU**. |
|||
|
|||
Также есть вероятность, что по какой-то причине возник **всплеск** запросов к вашему API. Возможно, это был вирус, боты или другие сервисы начали пользоваться им. И для таких происшествий вы можете захотеть иметь дополнительные ресурсы. |
|||
Также возможен **всплеск** использования вашего API: он мог «взорваться» по популярности, или какие‑то сервисы/боты начали его активно использовать. На такие случаи стоит иметь запас ресурсов. |
|||
|
|||
При настройке логики развёртываний, вы можете указать **целевое значение** утилизации ресурсов, допустим, **от 50% до 90%**. Обычно эти метрики и используют. |
|||
Можно задать **целевое значение**, например **между 50% и 90%** использования ресурсов. Скорее всего, именно эти вещи вы будете измерять и на их основе настраивать развёртывание. |
|||
|
|||
Вы можете использовать простые инструменты, такие как `htop`, для отслеживания загрузки центрального процессора и оперативной памяти сервера, в том числе каждым процессом. Или более сложные системы мониторинга нескольких серверов. |
|||
Можно использовать простые инструменты вроде `htop`, чтобы смотреть загрузку CPU и RAM на сервере или по процессам. Или более сложные распределённые системы мониторинга. |
|||
|
|||
## Резюме |
|||
## Резюме { #recap } |
|||
|
|||
Вы прочитали некоторые из основных концепций, которые необходимо иметь в виду при принятии решения о развертывании приложений: |
|||
Здесь вы прочитали о некоторых основных концепциях, которые, вероятно, стоит учитывать при выборе способа развёртывания приложения: |
|||
|
|||
* Использование более безопасного протокола HTTPS |
|||
* Настройки запуска приложения |
|||
* Перезагрузка приложения |
|||
* Запуск нескольких экземпляров приложения |
|||
* Управление памятью |
|||
* Использование перечисленных функций перед запуском приложения. |
|||
* Безопасность — HTTPS |
|||
* Запуск при старте |
|||
* Перезапуски |
|||
* Репликация (количество запущенных процессов) |
|||
* Память |
|||
* Предварительные шаги перед запуском |
|||
|
|||
Осознание этих идей и того, как их применять, должно дать Вам интуитивное понимание, необходимое для принятия решений при настройке развертываний. 🤓 |
|||
Понимание этих идей и того, как их применять, даст вам интуицию, необходимую для принятия решений при настройке и доработке ваших развёртываний. 🤓 |
|||
|
|||
В следующих разделах я приведу более конкретные примеры возможных стратегий, которым вы можете следовать. 🚀 |
|||
В следующих разделах я приведу более конкретные примеры возможных стратегий. 🚀 |
|||
|
@ -1,207 +1,231 @@ |
|||
# Об HTTPS |
|||
# Об HTTPS { #about-https } |
|||
|
|||
Обычно представляется, что HTTPS это некая опция, которая либо "включена", либо нет. |
|||
Легко предположить, что HTTPS — это что-то, что просто «включено» или нет. |
|||
|
|||
Но всё несколько сложнее. |
|||
Но на самом деле всё гораздо сложнее. |
|||
|
|||
/// tip | Заметка |
|||
/// tip | Совет |
|||
|
|||
Если вы торопитесь или вам не интересно, можете перейти на следующую страницу этого пошагового руководства по размещению приложений на серверах с использованием различных технологий. |
|||
Если вы торопитесь или вам это не важно, переходите к следующим разделам с пошаговыми инструкциями по настройке всего разными способами. |
|||
|
|||
/// |
|||
|
|||
Чтобы **изучить основы HTTPS** для клиента, перейдите по ссылке <a href="https://howhttps.works/" class="external-link" target="_blank">https://howhttps.works/</a>. |
|||
|
|||
Здесь же представлены некоторые концепции, которые **разработчик** должен иметь в виду при размышлениях об HTTPS: |
|||
|
|||
* Протокол HTTPS предполагает, что **серверу** нужно **располагать "сертификатами"** сгенерированными **третьей стороной**. |
|||
* На самом деле эти сертификаты **приобретены** у третьей стороны, а не "сгенерированы". |
|||
* У сертификатов есть **срок годности**. |
|||
* Срок годности **истекает**. |
|||
* По истечении срока годности их нужно **обновить**, то есть **снова получить** у третьей стороны. |
|||
* Шифрование соединения происходит **на уровне протокола TCP**. |
|||
* Протокол TCP находится на один уровень **ниже протокола HTTP**. |
|||
* Поэтому **проверка сертификатов и шифрование** происходит **до HTTP**. |
|||
* **TCP не знает о "доменах"**, но знает об IP-адресах. |
|||
* Информация о **запрашиваемом домене** извлекается из запроса **на уровне HTTP**. |
|||
* **Сертификаты HTTPS** "сертифицируют" **конкретный домен**, но проверка сертификатов и шифрование данных происходит на уровне протокола TCP, то есть **до того**, как станет известен домен-получатель данных. |
|||
* **По умолчанию** это означает, что у вас может быть **только один сертификат HTTPS на один IP-адрес**. |
|||
* Не важно, насколько большой у вас сервер и насколько маленькие приложения на нём могут быть. |
|||
* Однако, у этой проблемы есть **решение**. |
|||
* Существует **расширение** протокола **TLS** (который работает на уровне TCP, то есть до HTTP) называемое **<a href="https://en.wikipedia.org/wiki/Server_Name_Indication" class="external-link" target="_blank"><abbr title="Указание имени сервера">SNI</abbr></a>**. |
|||
* Расширение SNI позволяет одному серверу (с **одним IP-адресом**) иметь **несколько сертификатов HTTPS** и обслуживать **множество HTTPS-доменов/приложений**. |
|||
* Чтобы эта конструкция работала, **один** её компонент (программа) запущенный на сервере и слушающий **публичный IP-адрес**, должен иметь **все сертификаты HTTPS** для этого сервера. |
|||
* **После** установления защищённого соединения, протоколом передачи данных **остаётся HTTP**. |
|||
* Но данные теперь **зашифрованы**, несмотря на то, что они передаются по **протоколу HTTP**. |
|||
|
|||
Обычной практикой является иметь **одну программу/HTTP-сервер** запущенную на сервере (машине, хосте и т.д.) и **ответственную за всю работу с HTTPS**: |
|||
|
|||
* получение **зашифрованных HTTPS-запросов** |
|||
* отправка **расшифрованных HTTP запросов** в соответствующее HTTP-приложение, работающее на том же сервере (в нашем случае, это приложение **FastAPI**) |
|||
* получение **HTTP-ответа** от приложения |
|||
* **шифрование ответа** используя подходящий **сертификат HTTPS** |
|||
* отправка зашифрованного **HTTPS-ответа клиенту**. |
|||
Такой сервер часто называют **<a href="https://en.wikipedia.org/wiki/TLS_termination_proxy" class="external-link" target="_blank">Прокси-сервер завершения работы TLS</a>** или просто "прокси-сервер". |
|||
|
|||
Вот некоторые варианты, которые вы можете использовать в качестве такого прокси-сервера: |
|||
|
|||
* Traefik (может обновлять сертификаты) |
|||
* Caddy (может обновлять сертификаты) |
|||
Чтобы **изучить основы HTTPS** с точки зрения пользователя, загляните на <a href="https://howhttps.works/" class="external-link" target="_blank">https://howhttps.works/</a>. |
|||
|
|||
Теперь, со стороны **разработчика**, вот несколько вещей, которые стоит держать в голове, размышляя об HTTPS: |
|||
|
|||
* Для HTTPS **серверу** нужно **иметь «сертификаты»**, сгенерированные **третьей стороной**. |
|||
* Эти сертификаты на самом деле **приобретаются** у третьей стороны, а не «генерируются». |
|||
* У сертификатов есть **срок действия**. |
|||
* Они **истекают**. |
|||
* После этого их нужно **обновлять**, то есть **получать заново** у третьей стороны. |
|||
* Шифрование соединения происходит на **уровне TCP**. |
|||
* Это на один уровень **ниже HTTP**. |
|||
* Поэтому **сертификаты и шифрование** обрабатываются **до HTTP**. |
|||
* **TCP не знает о «доменах»**. Только об IP-адресах. |
|||
* Информация о **конкретном домене** передаётся в **данных HTTP**. |
|||
* **HTTPS-сертификаты** «сертифицируют» **определённый домен**, но протокол и шифрование происходят на уровне TCP, **до того как** становится известен домен, с которым идёт работа. |
|||
* **По умолчанию** это означает, что вы можете иметь **лишь один HTTPS-сертификат на один IP-адрес**. |
|||
* Неважно, насколько мощный у вас сервер или насколько маленькие приложения на нём работают. |
|||
* Однако у этого есть **решение**. |
|||
* Есть **расширение** протокола **TLS** (того самого, что занимается шифрованием на уровне TCP, до HTTP) под названием **<a href="https://en.wikipedia.org/wiki/Server_Name_Indication" class="external-link" target="_blank"><abbr title="Server Name Indication – Указание имени сервера">SNI</abbr></a>**. |
|||
* Это расширение SNI позволяет одному серверу (с **одним IP-адресом**) иметь **несколько HTTPS-сертификатов** и обслуживать **несколько HTTPS-доменов/приложений**. |
|||
* Чтобы это работало, **один** компонент (программа), запущенный на сервере и слушающий **публичный IP-адрес**, должен иметь **все HTTPS-сертификаты** на этом сервере. |
|||
* **После** установления защищённого соединения, протокол обмена данными — **всё ещё HTTP**. |
|||
* Содержимое **зашифровано**, несмотря на то, что оно отправляется по **протоколу HTTP**. |
|||
|
|||
Обычно на сервере (машине, хосте и т.п.) запускают **одну программу/HTTP‑сервер**, которая **управляет всей частью, связанной с HTTPS**: принимает **зашифрованные HTTPS-запросы**, отправляет **расшифрованные HTTP-запросы** в само HTTP‑приложение, работающее на том же сервере (в нашем случае это приложение **FastAPI**), получает **HTTP-ответ** от приложения, **шифрует его** с использованием подходящего **HTTPS‑сертификата** и отправляет клиенту по **HTTPS**. Такой сервер часто называют **<a href="https://en.wikipedia.org/wiki/TLS_termination_proxy" class="external-link" target="_blank">прокси‑сервером TLS-терминации</a>**. |
|||
|
|||
Некоторые варианты, которые вы можете использовать как прокси‑сервер TLS-терминации: |
|||
|
|||
* Traefik (умеет обновлять сертификаты) |
|||
* Caddy (умеет обновлять сертификаты) |
|||
* Nginx |
|||
* HAProxy |
|||
|
|||
## Let's Encrypt (центр сертификации) |
|||
## Let's Encrypt { #lets-encrypt } |
|||
|
|||
До появления Let's Encrypt **сертификаты HTTPS** приходилось покупать у третьих сторон. |
|||
До появления Let's Encrypt эти **HTTPS-сертификаты** продавались доверенными третьими сторонами. |
|||
|
|||
Процесс получения такого сертификата был трудоёмким, требовал предоставления подтверждающих документов и сертификаты стоили дорого. |
|||
Процесс получения таких сертификатов был неудобным, требовал бумажной волокиты, а сами сертификаты были довольно дорогими. |
|||
|
|||
Но затем консорциумом Linux Foundation был создан проект **<a href="https://letsencrypt.org/" class="external-link" target="_blank">Let's Encrypt</a>**. |
|||
Затем появился **<a href="https://letsencrypt.org/" class="external-link" target="_blank">Let's Encrypt</a>**. |
|||
|
|||
Он автоматически предоставляет **бесплатные сертификаты HTTPS**. Эти сертификаты используют все стандартные криптографические способы шифрования. Они имеют небольшой срок годности (около 3 месяцев), благодаря чему они даже **более безопасны**. |
|||
Это проект Linux Foundation. Он предоставляет **HTTPS‑сертификаты бесплатно**, в автоматическом режиме. Эти сертификаты используют стандартные криптографические механизмы и имеют короткий срок действия (около 3 месяцев), поэтому **безопасность фактически выше** благодаря уменьшенному сроку жизни. |
|||
|
|||
При запросе на получение сертификата, он автоматически генерируется и домен проверяется на безопасность. Это позволяет обновлять сертификаты автоматически. |
|||
Домены безопасно проверяются, а сертификаты выдаются автоматически. Это также позволяет автоматизировать процесс их продления. |
|||
|
|||
Суть идеи в автоматическом получении и обновлении этих сертификатов, чтобы все могли пользоваться **безопасным HTTPS. Бесплатно. В любое время.** |
|||
Идея — автоматизировать получение и продление сертификатов, чтобы у вас был **безопасный HTTPS, бесплатно и навсегда**. |
|||
|
|||
## HTTPS для разработчиков |
|||
## HTTPS для разработчиков { #https-for-developers } |
|||
|
|||
Ниже, шаг за шагом, с заострением внимания на идеях, важных для разработчика, описано, как может выглядеть HTTPS API. |
|||
Ниже приведён пример того, как может выглядеть HTTPS‑API, шаг за шагом, с акцентом на идеях, важных для разработчиков. |
|||
|
|||
### Имя домена |
|||
### Имя домена { #domain-name } |
|||
|
|||
Чаще всего, всё начинается с **приобретения имени домена**. Затем нужно настроить DNS-сервер (вероятно у того же провайдера, который выдал вам домен). |
|||
Чаще всего всё начинается с **приобретения** **имени домена**. Затем вы настраиваете его на DNS‑сервере (возможно, у того же облачного провайдера). |
|||
|
|||
Далее, возможно, вы получаете "облачный" сервер (виртуальную машину) или что-то типа этого, у которого есть <abbr title="Не изменяемый">постоянный</abbr> **публичный IP-адрес**. |
|||
Скорее всего, вы получите облачный сервер (виртуальную машину) или что-то подобное, и у него будет <abbr title="Не изменяется">постоянный</abbr> **публичный IP-адрес**. |
|||
|
|||
На DNS-сервере (серверах) вам следует настроить соответствующую ресурсную запись ("`запись A`"), указав, что **Ваш домен** связан с публичным **IP-адресом вашего сервера**. |
|||
На DNS‑сервере(ах) вы настроите запись («`A record`» - запись типа A), указывающую, что **ваш домен** должен указывать на публичный **IP‑адрес вашего сервера**. |
|||
|
|||
Обычно эту запись достаточно указать один раз, при первоначальной настройке всего сервера. |
|||
Обычно это делается один раз — при первоначальной настройке всего. |
|||
|
|||
/// tip | Заметка |
|||
/// tip | Совет |
|||
|
|||
Уровни протоколов, работающих с именами доменов, намного ниже HTTPS, но об этом следует упомянуть здесь, так как всё зависит от доменов и IP-адресов. |
|||
Часть про доменное имя относится к этапам задолго до HTTPS, но так как всё зависит от домена и IP‑адреса, здесь стоит это упомянуть. |
|||
|
|||
/// |
|||
|
|||
### DNS |
|||
### DNS { #dns } |
|||
|
|||
Теперь давайте сфокусируемся на работе с HTTPS. |
|||
Теперь сфокусируемся на собственно частях, связанных с HTTPS. |
|||
|
|||
Всё начинается с того, что браузер спрашивает у **DNS-серверов**, какой **IP-адрес связан с доменом**, для примера возьмём домен `someapp.example.com`. |
|||
Сначала браузер спросит у **DNS‑серверов**, какой **IP соответствует домену**, в нашем примере `someapp.example.com`. |
|||
|
|||
DNS-сервера присылают браузеру определённый **IP-адрес**, тот самый публичный IP-адрес вашего сервера, который вы указали в ресурсной "записи А" при настройке. |
|||
DNS‑серверы ответят браузеру, какой **конкретный IP‑адрес** использовать. Это будет публичный IP‑адрес вашего сервера, который вы указали в настройках DNS. |
|||
|
|||
<img src="/img/deployment/https/https01.drawio.svg"> |
|||
|
|||
### Рукопожатие TLS |
|||
### Начало TLS-рукопожатия { #tls-handshake-start } |
|||
|
|||
В дальнейшем браузер будет взаимодействовать с этим IP-адресом через **port 443** (общепринятый номер порта для HTTPS). |
|||
Далее браузер будет общаться с этим IP‑адресом на **порту 443** (порт HTTPS). |
|||
|
|||
Первым шагом будет установление соединения между клиентом (браузером) и сервером и выбор криптографического ключа (для шифрования). |
|||
Первая часть взаимодействия — установить соединение между клиентом и сервером и договориться о криптографических ключах и т.п. |
|||
|
|||
<img src="/img/deployment/https/https02.drawio.svg"> |
|||
|
|||
Эта часть клиент-серверного взаимодействия устанавливает TLS-соединение и называется **TLS-рукопожатием**. |
|||
Это взаимодействие клиента и сервера для установления TLS‑соединения называется **TLS‑рукопожатием**. |
|||
|
|||
### TLS с расширением SNI |
|||
### TLS с расширением SNI { #tls-with-sni-extension } |
|||
|
|||
На сервере **только один процесс** может прослушивать определённый **порт** определённого **IP-адреса**. На сервере могут быть и другие процессы, слушающие другие порты этого же IP-адреса, но никакой процесс не может быть привязан к уже занятой комбинации IP-адрес:порт. Эта комбинация называется "сокет". |
|||
На сервере **только один процесс** может слушать конкретный **порт** на конкретном **IP‑адресе**. Могут быть другие процессы, слушающие другие порты на том же IP‑адресе, но не более одного процесса на каждую комбинацию IP‑адреса и порта. |
|||
|
|||
По умолчанию TLS (HTTPS) использует порт `443`. Потому этот же порт будем использовать и мы. |
|||
По умолчанию TLS (HTTPS) использует порт `443`. Значит, он нам и нужен. |
|||
|
|||
И раз уж только один процесс может слушать этот порт, то это будет процесс **прокси-сервера завершения работы TLS**. |
|||
Так как только один процесс может слушать этот порт, делать это будет **прокси‑сервер TLS-терминации**. |
|||
|
|||
Прокси-сервер завершения работы TLS будет иметь доступ к одному или нескольким **TLS-сертификатам** (сертификаты HTTPS). |
|||
У прокси‑сервера TLS-терминации будет доступ к одному или нескольким **TLS‑сертификатам** (HTTPS‑сертификатам). |
|||
|
|||
Используя **расширение SNI** упомянутое выше, прокси-сервер из имеющихся сертификатов TLS (HTTPS) выберет тот, который соответствует имени домена, указанному в запросе от клиента. |
|||
Используя **расширение SNI**, упомянутое выше, прокси‑сервер TLS-терминации определит, какой из доступных TLS (HTTPS)‑сертификатов нужно использовать для этого соединения, выбрав тот, который соответствует домену, ожидаемому клиентом. |
|||
|
|||
То есть будет выбран сертификат для домена `someapp.example.com`. |
|||
В нашем случае это будет сертификат для `someapp.example.com`. |
|||
|
|||
<img src="/img/deployment/https/https03.drawio.svg"> |
|||
|
|||
Клиент уже **доверяет** тому, кто выдал этот TLS-сертификат (в нашем случае - Let's Encrypt, но мы ещё обсудим это), потому может **проверить**, действителен ли полученный от сервера сертификат. |
|||
Клиент уже **доверяет** организации, выдавшей этот TLS‑сертификат (в нашем случае — Let's Encrypt, но об этом позже), поэтому может **проверить**, что сертификат действителен. |
|||
|
|||
Затем, используя этот сертификат, клиент и прокси-сервер **выбирают способ шифрования** данных для устанавливаемого **TCP-соединения**. На этом операция **TLS-рукопожатия** завершена. |
|||
Затем, используя сертификат, клиент и прокси‑сервер TLS-терминации **договариваются о способе шифрования** остальной **TCP‑коммуникации**. На этом **TLS‑рукопожатие** завершено. |
|||
|
|||
В дальнейшем клиент и сервер будут взаимодействовать по **зашифрованному TCP-соединению**, как предлагается в протоколе TLS. И на основе этого TCP-соедениния будет создано **HTTP-соединение**. |
|||
После этого у клиента и сервера есть **зашифрованное TCP‑соединение** — это и предоставляет TLS. И они могут использовать это соединение, чтобы начать собственно **HTTP‑обмен**. |
|||
|
|||
Таким образом, **HTTPS** это тот же **HTTP**, но внутри **безопасного TLS-соединения** вместо чистого (незашифрованного) TCP-соединения. |
|||
Собственно, **HTTPS** — это обычный **HTTP** внутри **защищённого TLS‑соединения**, вместо чистого (незашифрованного) TCP‑соединения. |
|||
|
|||
/// tip | Заметка |
|||
/// tip | Совет |
|||
|
|||
Обратите внимание, что шифрование происходит на **уровне TCP**, а не на более высоком уровне HTTP. |
|||
Обратите внимание, что шифрование обмена происходит на **уровне TCP**, а не на уровне HTTP. |
|||
|
|||
/// |
|||
|
|||
### HTTPS-запрос |
|||
### HTTPS‑запрос { #https-request } |
|||
|
|||
Теперь, когда между клиентом и сервером (в нашем случае, браузером и прокси-сервером) создано **зашифрованное TCP-соединение**, они могут начать **обмен данными по протоколу HTTP**. |
|||
Теперь, когда у клиента и сервера (конкретно у браузера и прокси‑сервера TLS-терминации) есть **зашифрованное TCP‑соединение**, они могут начать **HTTP‑обмен**. |
|||
|
|||
Так клиент отправляет **HTTPS-запрос**. То есть обычный HTTP-запрос, но через зашифрованное TLS-содинение. |
|||
Клиент отправляет **HTTPS‑запрос**. Это обычный HTTP‑запрос через зашифрованное TLS‑соединение. |
|||
|
|||
<img src="/img/deployment/https/https04.drawio.svg"> |
|||
|
|||
### Расшифровка запроса |
|||
### Расшифровка запроса { #decrypt-the-request } |
|||
|
|||
Прокси-сервер, используя согласованный с клиентом ключ, расшифрует полученный **зашифрованный запрос** и передаст **обычный (незашифрованный) HTTP-запрос** процессу, запускающему приложение (например, процессу Uvicorn запускающему приложение FastAPI). |
|||
Прокси‑сервер TLS-терминации использует согласованное шифрование, чтобы **расшифровать запрос**, и передаёт **обычный (расшифрованный) HTTP‑запрос** процессу, запускающему приложение (например, процессу с Uvicorn, который запускает приложение FastAPI). |
|||
|
|||
<img src="/img/deployment/https/https05.drawio.svg"> |
|||
|
|||
### HTTP-ответ |
|||
### HTTP‑ответ { #http-response } |
|||
|
|||
Приложение обработает запрос и вернёт **обычный (незашифрованный) HTTP-ответ** прокси-серверу. |
|||
Приложение обработает запрос и отправит **обычный (незашифрованный) HTTP‑ответ** прокси‑серверу TLS-терминации. |
|||
|
|||
<img src="/img/deployment/https/https06.drawio.svg"> |
|||
|
|||
### HTTPS-ответ |
|||
### HTTPS‑ответ { #https-response } |
|||
|
|||
Пркоси-сервер **зашифрует ответ** используя ранее согласованный с клиентом способ шифрования (которые содержатся в сертификате для домена `someapp.example.com`) и отправит его браузеру. |
|||
Затем прокси‑сервер TLS-терминации **зашифрует ответ** с использованием ранее согласованного способа шифрования (который начали использовать для сертификата для `someapp.example.com`) и отправит его обратно в браузер. |
|||
|
|||
Наконец, браузер проверит ответ, в том числе, что тот зашифрован с нужным ключом, **расшифрует его** и обработает. |
|||
Далее браузер проверит, что ответ корректен и зашифрован правильным криптографическим ключом и т.п., затем **расшифрует ответ** и обработает его. |
|||
|
|||
<img src="/img/deployment/https/https07.drawio.svg"> |
|||
|
|||
Клиент (браузер) знает, что ответ пришёл от правильного сервера, так как использует методы шифрования, согласованные ими раннее через **HTTPS-сертификат**. |
|||
Клиент (браузер) узнает, что ответ пришёл от правильного сервера, потому что используется способ шифрования, о котором они договорились ранее с помощью **HTTPS‑сертификата**. |
|||
|
|||
### Множество приложений |
|||
### Несколько приложений { #multiple-applications } |
|||
|
|||
На одном и том же сервере (или серверах) можно разместить **множество приложений**, например, другие программы с API или базы данных. |
|||
На одном и том же сервере (или серверах) могут работать **несколько приложений**, например другие программы с API или база данных. |
|||
|
|||
Напомню, что только один процесс (например, прокси-сервер) может прослушивать определённый порт определённого IP-адреса. |
|||
Но другие процессы и приложения тоже могут работать на этом же сервере (серверах), если они не пытаются использовать уже занятую **комбинацию IP-адреса и порта** (сокет). |
|||
Только один процесс может обрабатывать конкретную комбинацию IP и порта (в нашем примере — прокси‑сервер TLS-терминации), но остальные приложения/процессы тоже могут работать на сервере(ах), пока они не пытаются использовать ту же **комбинацию публичного IP и порта**. |
|||
|
|||
<img src="/img/deployment/https/https08.drawio.svg"> |
|||
|
|||
Таким образом, сервер завершения TLS может обрабатывать HTTPS-запросы и использовать сертификаты для **множества доменов** или приложений и передавать запросы правильным адресатам (другим приложениям). |
|||
Таким образом, прокси‑сервер TLS-терминации может обрабатывать HTTPS и сертификаты для **нескольких доменов** (для нескольких приложений), а затем передавать запросы нужному приложению в каждом случае. |
|||
|
|||
### Обновление сертификата |
|||
### Продление сертификата { #certificate-renewal } |
|||
|
|||
В недалёком будущем любой сертификат станет **просроченным** (примерно через три месяца после получения). |
|||
Со временем каждый сертификат **истечёт** (примерно через 3 месяца после получения). |
|||
|
|||
Когда это произойдёт, можно запустить другую программу, которая подключится к Let's Encrypt и обновит сертификат(ы). Существуют прокси-серверы, которые могут сделать это действие самостоятельно. |
|||
Затем будет другая программа (иногда это отдельная программа, иногда — тот же прокси‑сервер TLS-терминации), которая свяжется с Let's Encrypt и продлит сертификат(ы). |
|||
|
|||
<img src="/img/deployment/https/https.drawio.svg"> |
|||
|
|||
**TLS-сертификаты** не привязаны к IP-адресу, но **связаны с именем домена**. |
|||
**TLS‑сертификаты** **связаны с именем домена**, а не с IP‑адресом. |
|||
|
|||
Так что при обновлении сертификатов программа должна **подтвердить** центру сертификации (Let's Encrypt), что обновление запросил **"владелец", который контролирует этот домен**. |
|||
Поэтому, чтобы продлить сертификаты, программа продления должна **доказать** удостоверяющему центру (Let's Encrypt), что она действительно **«владеет» и контролирует этот домен**. |
|||
|
|||
Есть несколько путей осуществления этого. Самые популярные из них: |
|||
Для этого, учитывая разные потребности приложений, есть несколько способов. Популярные из них: |
|||
|
|||
* **Изменение записей DNS**. |
|||
* Для такого варианта Ваша программа обновления должна уметь работать с API DNS-провайдера, обслуживающего Ваши DNS-записи. Не у всех провайдеров есть такой API, так что этот способ не всегда применим. |
|||
* **Запуск в качестве программы-сервера** (как минимум, на время обновления сертификатов) на публичном IP-адресе домена. |
|||
* Как уже не раз упоминалось, только один процесс может прослушивать определённый порт определённого IP-адреса. |
|||
* Это одна из причин использования прокси-сервера ещё и в качестве программы обновления сертификатов. |
|||
* В случае, если обновлением сертификатов занимается другая программа, вам понадобится остановить прокси-сервер, запустить программу обновления сертификатов на сокете, предназначенном для прокси-сервера, настроить прокси-сервер на работу с новыми сертификатами и перезапустить его. Эта схема далека от идеальной, так как Ваши приложения будут недоступны на время отключения прокси-сервера. |
|||
* **Изменить некоторые DNS‑записи**. |
|||
* Для этого программа продления должна поддерживать API DNS‑провайдера, поэтому, в зависимости от используемого провайдера DNS, этот вариант может быть доступен или нет. |
|||
* **Запуститься как сервер** (как минимум на время получения сертификатов) на публичном IP‑адресе, связанном с доменом. |
|||
* Как сказано выше, только один процесс может слушать конкретный IP и порт. |
|||
* Это одна из причин, почему очень удобно, когда тот же прокси‑сервер TLS-терминации также занимается процессом продления сертификатов. |
|||
* В противном случае вам, возможно, придётся временно остановить прокси‑сервер TLS-терминации, запустить программу продления для получения сертификатов, затем настроить их в прокси‑сервере TLS-терминации и перезапустить его. Это не идеально, так как ваше приложение(я) будут недоступны, пока прокси‑сервер TLS-терминации остановлен. |
|||
|
|||
Весь этот процесс обновления, одновременный с обслуживанием запросов, является одной из основных причин, по которой желательно иметь **отдельную систему для работы с HTTPS** в виде прокси-сервера завершения TLS, а не просто использовать сертификаты TLS непосредственно с сервером приложений (например, Uvicorn). |
|||
Весь этот процесс продления, совмещённый с обслуживанием приложения, — одна из главных причин иметь **отдельную систему для работы с HTTPS** в виде прокси‑сервера TLS-терминации, вместо использования TLS‑сертификатов напрямую в сервере приложения (например, Uvicorn). |
|||
|
|||
## Резюме |
|||
## Пересылаемые HTTP-заголовки прокси { #proxy-forwarded-headers } |
|||
|
|||
Наличие **HTTPS** очень важно и довольно **критично** в большинстве случаев. Однако, Вам, как разработчику, не нужно тратить много сил на это, достаточно **понимать эти концепции** и принципы их работы. |
|||
Когда вы используете прокси для обработки HTTPS, ваш **сервер приложения** (например, Uvicorn через FastAPI CLI) ничего не знает о процессе HTTPS, он общается обычным HTTP с **прокси‑сервером TLS-терминации**. |
|||
|
|||
Но узнав базовые основы **HTTPS** вы можете легко совмещать разные инструменты, которые помогут вам в дальнейшей разработке. |
|||
Обычно этот **прокси** на лету добавляет некоторые HTTP‑заголовки перед тем, как переслать запрос на **сервер приложения**, чтобы тот знал, что запрос был **проксирован**. |
|||
|
|||
В следующих главах я покажу вам несколько примеров, как настраивать **HTTPS** для приложений **FastAPI**. 🔒 |
|||
/// note | Технические детали |
|||
|
|||
Заголовки прокси: |
|||
|
|||
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For" class="external-link" target="_blank">X-Forwarded-For</a> |
|||
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto" class="external-link" target="_blank">X-Forwarded-Proto</a> |
|||
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host" class="external-link" target="_blank">X-Forwarded-Host</a> |
|||
|
|||
/// |
|||
|
|||
Тем не менее, так как **сервер приложения** не знает, что он находится за доверенным **прокси**, по умолчанию он не будет доверять этим заголовкам. |
|||
|
|||
Но вы можете настроить **сервер приложения**, чтобы он доверял *пересылаемым* заголовкам, отправленным **прокси**. Если вы используете FastAPI CLI, вы можете использовать *опцию CLI* `--forwarded-allow-ips`, чтобы указать, с каких IP‑адресов следует доверять этим *пересылаемым* заголовкам. |
|||
|
|||
Например, если **сервер приложения** получает запросы только от доверенного **прокси**, вы можете установить `--forwarded-allow-ips="*"`, чтобы доверять всем входящим IP, так как он всё равно будет получать запросы только с IP‑адреса, используемого **прокси**. |
|||
|
|||
Таким образом, приложение сможет знать свой публичный URL, использует ли оно HTTPS, какой домен и т.п. |
|||
|
|||
Это будет полезно, например, для корректной обработки редиректов. |
|||
|
|||
/// tip | Совет |
|||
|
|||
Подробнее об этом вы можете узнать в документации: [За прокси — Включить пересылаемые заголовки прокси](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers){.internal-link target=_blank} |
|||
|
|||
/// |
|||
|
|||
## Резюме { #recap } |
|||
|
|||
Наличие **HTTPS** очень важно и во многих случаях довольно **критично**. Большая часть усилий, которые вам, как разработчику, нужно приложить вокруг HTTPS, — это просто **понимание этих концепций** и того, как они работают. |
|||
|
|||
Зная базовую информацию о **HTTPS для разработчиков**, вы сможете легко комбинировать и настраивать разные инструменты, чтобы управлять всем этим простым способом. |
|||
|
|||
В некоторых из следующих глав я покажу вам несколько конкретных примеров настройки **HTTPS** для приложений **FastAPI**. 🔒 |
|||
|
@ -1,163 +1,157 @@ |
|||
# Запуск сервера вручную - Uvicorn |
|||
# Запуск сервера вручную { #run-a-server-manually } |
|||
|
|||
Для запуска приложения **FastAPI** на удалённой серверной машине вам необходим программный сервер, поддерживающий протокол ASGI, такой как **Uvicorn**. |
|||
## Используйте команду `fastapi run` { #use-the-fastapi-run-command } |
|||
|
|||
Существует три наиболее распространённые альтернативы: |
|||
Коротко: используйте `fastapi run`, чтобы запустить ваше приложение FastAPI: |
|||
|
|||
* <a href="https://www.uvicorn.org/" class="external-link" target="_blank">Uvicorn</a>: высокопроизводительный ASGI сервер. |
|||
* <a href="https://hypercorn.readthedocs.io/" class="external-link" target="_blank">Hypercorn</a>: ASGI сервер, помимо прочего поддерживающий HTTP/2 и Trio. |
|||
* <a href="https://github.com/django/daphne" class="external-link" target="_blank">Daphne</a>: ASGI сервер, созданный для Django Channels. |
|||
|
|||
## Сервер как машина и сервер как программа |
|||
|
|||
В этих терминах есть некоторые различия и вам следует запомнить их. 💡 |
|||
|
|||
Слово "**сервер**" чаще всего используется в двух контекстах: |
|||
<div class="termy"> |
|||
|
|||
- удалённый или расположенный в "облаке" компьютер (физическая или виртуальная машина). |
|||
- программа, запущенная на таком компьютере (например, Uvicorn). |
|||
```console |
|||
$ <font color="#4E9A06">fastapi</font> run <u style="text-decoration-style:solid">main.py</u> |
|||
|
|||
Просто запомните, если вам встретился термин "сервер", то обычно он подразумевает что-то из этих двух смыслов. |
|||
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting production server 🚀 |
|||
|
|||
Когда имеют в виду именно удалённый компьютер, часто говорят просто **сервер**, но ещё его называют **машина**, **ВМ** (виртуальная машина), **нода**. Все эти термины обозначают одно и то же - удалённый компьютер, обычно под управлением Linux, на котором вы запускаете программы. |
|||
Searching for package file structure from directories |
|||
with <font color="#3465A4">__init__.py</font> files |
|||
Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font> |
|||
|
|||
## Установка программного сервера |
|||
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py |
|||
|
|||
Вы можете установить сервер, совместимый с протоколом ASGI, так: |
|||
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with |
|||
the following code: |
|||
|
|||
//// tab | Uvicorn |
|||
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u> |
|||
|
|||
* <a href="https://www.uvicorn.org/" class="external-link" target="_blank">Uvicorn</a>, очень быстрый ASGI сервер, основанный на библиотеках uvloop и httptools. |
|||
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font> |
|||
|
|||
<div class="termy"> |
|||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000</u></font> |
|||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000/docs</u></font> |
|||
|
|||
```console |
|||
$ pip install "uvicorn[standard]" |
|||
Logs: |
|||
|
|||
---> 100% |
|||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>2306215</b></font><b>]</b> |
|||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup. |
|||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete. |
|||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C |
|||
to quit<b>)</b> |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
/// tip | Подсказка |
|||
|
|||
С опцией `standard`, Uvicorn будет устанавливаться и использоваться с некоторыми дополнительными рекомендованными зависимостями. |
|||
|
|||
В них входит `uvloop`, высокопроизводительная замена `asyncio`, которая значительно ускоряет работу асинхронных программ. |
|||
|
|||
/// |
|||
|
|||
//// |
|||
В большинстве случаев этого достаточно. 😎 |
|||
|
|||
//// tab | Hypercorn |
|||
Этой командой, например, можно запускать приложение **FastAPI** в контейнере, на сервере и т.д. |
|||
|
|||
* <a href="https://github.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>, ASGI сервер, поддерживающий протокол HTTP/2. |
|||
## ASGI‑серверы { #asgi-servers } |
|||
|
|||
<div class="termy"> |
|||
Давайте немного углубимся в детали. |
|||
|
|||
```console |
|||
$ pip install hypercorn |
|||
FastAPI использует стандарт для построения Python‑веб‑фреймворков и серверов под названием <abbr title="Asynchronous Server Gateway Interface – Асинхронный шлюзовый интерфейс сервера">ASGI</abbr>. FastAPI — ASGI-веб‑фреймворк. |
|||
|
|||
---> 100% |
|||
``` |
|||
Главное, что вам нужно, чтобы запустить приложение **FastAPI** (или любое другое ASGI‑приложение) на удалённой серверной машине, — это программа ASGI‑сервера, такая как **Uvicorn**; именно он используется по умолчанию в команде `fastapi`. |
|||
|
|||
</div> |
|||
Есть несколько альтернатив, например: |
|||
|
|||
...или какой-либо другой ASGI сервер. |
|||
* <a href="https://www.uvicorn.org/" class="external-link" target="_blank">Uvicorn</a>: высокопроизводительный ASGI‑сервер. |
|||
* <a href="https://hypercorn.readthedocs.io/" class="external-link" target="_blank">Hypercorn</a>: ASGI‑сервер, среди прочего совместимый с HTTP/2 и Trio. |
|||
* <a href="https://github.com/django/daphne" class="external-link" target="_blank">Daphne</a>: ASGI‑сервер, созданный для Django Channels. |
|||
* <a href="https://github.com/emmett-framework/granian" class="external-link" target="_blank">Granian</a>: HTTP‑сервер на Rust для Python‑приложений. |
|||
* <a href="https://unit.nginx.org/howto/fastapi/" class="external-link" target="_blank">NGINX Unit</a>: NGINX Unit — лёгкая и многофункциональная среда выполнения веб‑приложений. |
|||
|
|||
//// |
|||
## Сервер как машина и сервер как программа { #server-machine-and-server-program } |
|||
|
|||
## Запуск серверной программы |
|||
Есть небольшой нюанс в терминологии, о котором стоит помнить. 💡 |
|||
|
|||
Затем запустите ваше приложение так же, как было указано в руководстве ранее, но без опции `--reload`: |
|||
Слово «сервер» обычно используют и для обозначения удалённого/облачного компьютера (физической или виртуальной машины), и для программы, работающей на этой машине (например, Uvicorn). |
|||
|
|||
//// tab | Uvicorn |
|||
Имейте в виду, что слово «сервер» в целом может означать любое из этих двух. |
|||
|
|||
<div class="termy"> |
|||
Когда речь идёт об удалённой машине, её зачастую называют **сервер**, а также **машина**, **VM** (виртуальная машина), **нода**. Всё это — варианты названия удалённой машины, обычно под управлением Linux, на которой вы запускаете программы. |
|||
|
|||
```console |
|||
$ uvicorn main:app --host 0.0.0.0 --port 80 |
|||
## Установка серверной программы { #install-the-server-program } |
|||
|
|||
<span style="color: green;">INFO</span>: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit) |
|||
``` |
|||
При установке FastAPI он поставляется с продакшн‑сервером Uvicorn, и вы можете запустить его командой `fastapi run`. |
|||
|
|||
</div> |
|||
Но вы также можете установить ASGI‑сервер вручную. |
|||
|
|||
//// |
|||
Создайте [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активируйте его и затем установите серверное приложение. |
|||
|
|||
//// tab | Hypercorn |
|||
Например, чтобы установить Uvicorn: |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ hypercorn main:app --bind 0.0.0.0:80 |
|||
$ pip install "uvicorn[standard]" |
|||
|
|||
Running on 0.0.0.0:8080 over http (CTRL + C to quit) |
|||
---> 100% |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
//// |
|||
Аналогично устанавливаются и другие ASGI‑серверы. |
|||
|
|||
/// warning | Предупреждение |
|||
/// tip | Совет |
|||
|
|||
Не забудьте удалить опцию `--reload`, если ранее пользовались ею. |
|||
С добавлением `standard` Uvicorn установит и будет использовать ряд рекомендованных дополнительных зависимостей. |
|||
|
|||
Включение опции `--reload` требует дополнительных ресурсов, влияет на стабильность работы приложения и может повлечь прочие неприятности. |
|||
В их числе `uvloop` — высокопроизводительная замена `asyncio`, дающая серьёзный прирост производительности при параллельной работе. |
|||
|
|||
Она сильно помогает во время **разработки**, но **не следует** использовать её при **реальной работе** приложения. |
|||
Если вы устанавливаете FastAPI, например так: `pip install "fastapi[standard]"`, вы уже получаете и `uvicorn[standard]`. |
|||
|
|||
/// |
|||
|
|||
## Hypercorn с Trio |
|||
|
|||
Starlette и **FastAPI** основаны на <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>, которая делает их совместимыми как с <a href="https://docs.python.org/3/library/asyncio-task.html" class="external-link" target="_blank">asyncio</a> - стандартной библиотекой Python, так и с <a href="https://trio.readthedocs.io/en/stable/" class="external-link" target="_blank">Trio</a>. |
|||
|
|||
## Запуск серверной программы { #run-the-server-program } |
|||
|
|||
Тем не менее Uvicorn совместим только с asyncio и обычно используется совместно с <a href="https://github.com/MagicStack/uvloop" class="external-link" target="_blank">`uvloop`</a>, высокопроизводительной заменой `asyncio`. |
|||
|
|||
Но если вы хотите использовать **Trio** напрямую, то можете воспользоваться **Hypercorn**, так как они совместимы. ✨ |
|||
|
|||
### Установка Hypercorn с Trio |
|||
|
|||
Для начала, вам нужно установить Hypercorn с поддержкой Trio: |
|||
Если вы установили ASGI‑сервер вручную, обычно нужно передать строку импорта в специальном формате, чтобы он смог импортировать ваше приложение FastAPI: |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ pip install "hypercorn[trio]" |
|||
---> 100% |
|||
$ uvicorn main:app --host 0.0.0.0 --port 80 |
|||
|
|||
<span style="color: green;">INFO</span>: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit) |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
### Запуск с Trio |
|||
/// note | Примечание |
|||
|
|||
Далее запустите Hypercorn с опцией `--worker-class` и аргументом `trio`: |
|||
Команда `uvicorn main:app` означает: |
|||
|
|||
<div class="termy"> |
|||
* `main`: файл `main.py` (Python‑«модуль»). |
|||
* `app`: объект, созданный в `main.py` строкой `app = FastAPI()`. |
|||
|
|||
```console |
|||
$ hypercorn main:app --worker-class trio |
|||
Эквивалентно: |
|||
|
|||
```Python |
|||
from main import app |
|||
``` |
|||
|
|||
</div> |
|||
/// |
|||
|
|||
Hypercorn, в свою очередь, запустит ваше приложение использующее Trio. |
|||
У каждого альтернативного ASGI‑сервера будет похожая команда; подробнее см. в их документации. |
|||
|
|||
Таким образом, вы сможете использовать Trio в своём приложении. Но лучше использовать AnyIO, для сохранения совместимости и с Trio, и с asyncio. 🎉 |
|||
/// warning | Предупреждение |
|||
|
|||
Uvicorn и другие серверы поддерживают опцию `--reload`, полезную в период разработки. |
|||
|
|||
Опция `--reload` потребляет значительно больше ресурсов, менее стабильна и т.п. |
|||
|
|||
Она сильно помогает во время **разработки**, но в **продакшн** её использовать **не следует**. |
|||
|
|||
/// |
|||
|
|||
## Концепции развёртывания |
|||
## Концепции развёртывания { #deployment-concepts } |
|||
|
|||
В вышеприведённых примерах серверные программы (например Uvicorn) запускали только **один процесс**, принимающий входящие запросы с любого IP (на это указывал аргумент `0.0.0.0`) на определённый порт (в примерах мы указывали порт `80`). |
|||
В этих примерах серверная программа (например, Uvicorn) запускает **один процесс**, слушающий все IP‑адреса (`0.0.0.0`) на заранее заданном порту (например, `80`). |
|||
|
|||
Это основная идея. Но возможно, вы озаботитесь добавлением дополнительных возможностей, таких как: |
|||
Это базовая идея. Но, вероятно, вам понадобится позаботиться и о некоторых дополнительных вещах, например: |
|||
|
|||
* Использование более безопасного протокола HTTPS |
|||
* Настройки запуска приложения |
|||
* Перезагрузка приложения |
|||
* Запуск нескольких экземпляров приложения |
|||
* Управление памятью |
|||
* Использование перечисленных функций перед запуском приложения. |
|||
* Безопасность — HTTPS |
|||
* Запуск при старте системы |
|||
* Перезапуски |
|||
* Репликация (количество запущенных процессов) |
|||
* Память |
|||
* Предварительные шаги перед запуском |
|||
|
|||
Я расскажу вам больше о каждой из этих концепций в следующих главах, с конкретными примерами стратегий работы с ними. 🚀 |
|||
В следующих главах я расскажу подробнее про каждую из этих концепций, о том, как о них думать, и приведу конкретные примеры со стратегиями, как с ними работать. 🚀 |
|||
|
@ -1,261 +1,255 @@ |
|||
# Помочь FastAPI - Получить помощь |
|||
# Помочь FastAPI - Получить помощь { #help-fastapi-get-help } |
|||
|
|||
Нравится ли Вам **FastAPI**? |
|||
|
|||
Хотели бы Вы помочь FastAPI, его пользователям и автору? |
|||
Хотели бы Вы помочь FastAPI, другим пользователям и автору? |
|||
|
|||
Может быть у Вас возникли трудности с **FastAPI** и Вам нужна помощь? |
|||
Или Вы хотите получить помощь по **FastAPI**? |
|||
|
|||
Есть несколько очень простых способов оказания помощи (иногда достаточно всего лишь одного или двух кликов). |
|||
Есть несколько очень простых способов помочь (иногда достаточно всего лишь одного-двух кликов). |
|||
|
|||
И также есть несколько способов получить помощь. |
|||
|
|||
## Подписаться на новостную рассылку |
|||
## Подписаться на новостную рассылку { #subscribe-to-the-newsletter } |
|||
|
|||
Вы можете подписаться на редкую [новостную рассылку **FastAPI и его друзья**](newsletter.md){.internal-link target=_blank} и быть в курсе о: |
|||
|
|||
* Новостях о FastAPI и его друзьях 🚀 |
|||
* Руководствах 📝 |
|||
* Возможностях ✨ |
|||
* Исправлениях 🚨 |
|||
* Ломающих изменениях 🚨 |
|||
* Подсказках и хитростях ✅ |
|||
|
|||
## Подписаться на FastAPI в X (Twitter) |
|||
## Подписаться на FastAPI в X (Twitter) { #follow-fastapi-on-x-twitter } |
|||
|
|||
<a href="https://x.com/fastapi" class="external-link" target="_blank">Подписаться на @fastapi в **X (Twitter)**</a> для получения наисвежайших новостей о **FastAPI**. 🐦 |
|||
|
|||
## Добавить **FastAPI** звезду на GitHub |
|||
## Добавить **FastAPI** звезду на GitHub { #star-fastapi-in-github } |
|||
|
|||
Вы можете добавить FastAPI "звезду" на GitHub (кликнуть на кнопку звезды в верхнем правом углу экрана): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. ⭐️ |
|||
Вы можете добавить FastAPI "звезду" на GitHub (кликнув на кнопку звезды в правом верхнем углу): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. ⭐️ |
|||
|
|||
Чем больше звёзд, тем легче другим пользователям найти нас и увидеть, что проект уже стал полезным для многих. |
|||
Чем больше звёзд, тем легче другим пользователям найти проект и увидеть, что он уже оказался полезным для многих. |
|||
|
|||
## Отслеживать свежие выпуски в репозитории на GitHub |
|||
## Отслеживать свежие выпуски в репозитории на GitHub { #watch-the-github-repository-for-releases } |
|||
|
|||
Вы можете "отслеживать" FastAPI на GitHub (кликните по кнопке "watch" наверху справа): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. 👀 |
|||
Вы можете "отслеживать" FastAPI на GitHub (кликнув по кнопке "watch" наверху справа): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. 👀 |
|||
|
|||
Там же Вы можете указать в настройках - "Releases only". |
|||
Там же Вы можете выбрать "Releases only". |
|||
|
|||
С такой настройкой Вы будете получать уведомления на вашу электронную почту каждый раз, когда появится новый релиз (новая версия) **FastAPI** с исправлениями ошибок и новыми возможностями. |
|||
|
|||
## Связаться с автором |
|||
## Связаться с автором { #connect-with-the-author } |
|||
|
|||
Можно связаться со <a href="https://tiangolo.com" class="external-link" target="_blank">мной (Себястьян Рамирез / `tiangolo`)</a>, автором FastAPI. |
|||
Можно связаться со <a href="https://tiangolo.com" class="external-link" target="_blank">мной (Sebastián Ramírez / `tiangolo`)</a>, автором. |
|||
|
|||
Вы можете: |
|||
|
|||
* <a href="https://github.com/tiangolo" class="external-link" target="_blank">Подписаться на меня на **GitHub**</a>. |
|||
* Посмотреть другие мои проекты с открытым кодом, которые могут быть полезны Вам. |
|||
* Подписавшись на меня Вы сможете получать уведомления, что я создал новый проект с открытым кодом,. |
|||
* Подписаться, чтобы видеть, когда я создаю новый проект с открытым кодом. |
|||
* <a href="https://x.com/tiangolo" class="external-link" target="_blank">Подписаться на меня в **X (Twitter)**</a> или в <a href="https://fosstodon.org/@tiangolo" class="external-link" target="_blank">Mastodon</a>. |
|||
* Поделиться со мной, как Вы используете FastAPI (я обожаю читать про это). |
|||
* Получать уведомления, когда я делаю объявления и представляю новые инструменты. |
|||
* Поделиться со мной, как Вы используете FastAPI (я обожаю это читать). |
|||
* Узнавать, когда я делаю объявления или выпускаю новые инструменты. |
|||
* Вы также можете <a href="https://x.com/fastapi" class="external-link" target="_blank">подписаться на @fastapi в X (Twitter)</a> (это отдельный аккаунт). |
|||
* <a href="https://www.linkedin.com/in/tiangolo/" class="external-link" target="_blank">Подписаться на меня в **Linkedin**</a>. |
|||
* Получать уведомления, когда я делаю объявления и представляю новые инструменты (правда чаще всего я использую X (Twitter) 🤷♂). |
|||
* Читать, что я пишу (или подписаться на меня) в <a href="https://dev.to/tiangolo" class="external-link" target="_blank">**Dev.to**</a> или в <a href="https://medium.com/@tiangolo" class="external-link" target="_blank">**Medium**</a>. |
|||
* Читать другие идеи, статьи и читать об инструментах созданных мной. |
|||
* Подпишитесь на меня, чтобы прочитать, когда я опубликую что-нибудь новое. |
|||
* <a href="https://www.linkedin.com/in/tiangolo/" class="external-link" target="_blank">Подписаться на меня в **LinkedIn**</a>. |
|||
* Узнавать, когда я делаю объявления или выпускаю новые инструменты (хотя чаще я использую X (Twitter) 🤷♂). |
|||
* Читать, что я пишу (или подписаться на меня) на <a href="https://dev.to/tiangolo" class="external-link" target="_blank">**Dev.to**</a> или <a href="https://medium.com/@tiangolo" class="external-link" target="_blank">**Medium**</a>. |
|||
* Читать другие идеи, статьи и о созданных мной инструментах. |
|||
* Подписаться, чтобы читать, когда я публикую что-то новое. |
|||
|
|||
## Оставить сообщение в X (Twitter) о **FastAPI** |
|||
## Оставить сообщение в X (Twitter) о **FastAPI** { #tweet-about-fastapi } |
|||
|
|||
<a href="https://x.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi" class="external-link" target="_blank">Оставьте сообщение в X (Twitter) о **FastAPI**</a> и позвольте мне и другим узнать - почему он Вам нравится. 🎉 |
|||
<a href="https://x.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi" class="external-link" target="_blank">Оставьте сообщение в X (Twitter) о **FastAPI**</a> и позвольте мне и другим узнать, почему он Вам нравится. 🎉 |
|||
|
|||
Я люблю узнавать о том, как **FastAPI** используется, что Вам понравилось в нём, в каких проектах/компаниях Вы используете его и т.п. |
|||
Я люблю узнавать о том, как **FastAPI** используется, что Вам понравилось в нём, в каких проектах/компаниях Вы его используете и т.д. |
|||
|
|||
## Оставить голос за FastAPI |
|||
## Оставить голос за FastAPI { #vote-for-fastapi } |
|||
|
|||
* <a href="https://www.slant.co/options/34241/~fastapi-review" class="external-link" target="_blank">Голосуйте за **FastAPI** в Slant</a>. |
|||
* <a href="https://alternativeto.net/software/fastapi/" class="external-link" target="_blank">Голосуйте за **FastAPI** в AlternativeTo</a>. |
|||
* <a href="https://stackshare.io/pypi-fastapi" class="external-link" target="_blank">Расскажите, как Вы используете **FastAPI** на StackShare</a>. |
|||
* <a href="https://alternativeto.net/software/fastapi/about/" class="external-link" target="_blank">Голосуйте за **FastAPI** в AlternativeTo</a>. |
|||
* <a href="https://stackshare.io/pypi-fastapi" class="external-link" target="_blank">Расскажите, что Вы используете **FastAPI** на StackShare</a>. |
|||
|
|||
## Помочь другим с их проблемами на GitHub |
|||
## Помочь другим с вопросами на GitHub { #help-others-with-questions-in-github } |
|||
|
|||
Вы можете посмотреть, какие <a href="https://github.com/fastapi/fastapi/issues" class="external-link" target="_blank">проблемы</a> испытывают другие люди и попытаться помочь им. Чаще всего это вопросы, на которые, весьма вероятно, Вы уже знаете ответ. 🤓 |
|||
Вы можете попробовать помочь другим с их вопросами в: |
|||
|
|||
Если Вы будете много помогать людям с решением их проблем, Вы можете стать официальным [Экспертом FastAPI](fastapi-people.md#_3){.internal-link target=_blank}. 🎉 |
|||
* <a href="https://github.com/fastapi/fastapi/discussions/categories/questions?discussions_q=category%3AQuestions+is%3Aunanswered" class="external-link" target="_blank">GitHub Discussions</a> |
|||
* <a href="https://github.com/fastapi/fastapi/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aquestion+-label%3Aanswered+" class="external-link" target="_blank">GitHub Issues</a> |
|||
|
|||
Только помните, самое важное при этом - доброта. Столкнувшись с проблемой, люди расстраиваются и часто задают вопросы не лучшим образом, но постарайтесь быть максимально доброжелательным. 🤗 |
|||
Во многих случаях Вы уже можете знать ответы на эти вопросы. 🤓 |
|||
|
|||
Идея сообщества **FastAPI** в том, чтобы быть добродушным и гостеприимными. Не допускайте издевательств или неуважительного поведения по отношению к другим. Мы должны заботиться друг о друге. |
|||
Если Вы много помогаете людям с их вопросами, Вы станете официальным [Экспертом FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}. 🎉 |
|||
|
|||
Только помните, самое важное — постарайтесь быть добрыми. Люди приходят со своими разочарованиями и часто задают вопросы не лучшим образом, но постарайтесь, насколько можете, быть доброжелательными. 🤗 |
|||
|
|||
Идея сообщества **FastAPI** — быть доброжелательным и гостеприимным. В то же время не допускайте травлю или неуважительное поведение по отношению к другим. Мы должны заботиться друг о друге. |
|||
|
|||
--- |
|||
|
|||
Как помочь другим с их проблемами: |
|||
Как помочь другим с вопросами (в обсуждениях или Issues): |
|||
|
|||
### Понять вопрос |
|||
### Понять вопрос { #understand-the-question } |
|||
|
|||
* Удостоверьтесь, что поняли **цель** и обстоятельства случая вопрошающего. |
|||
* Убедитесь, что поняли **цель** и кейс использования задающего вопрос. |
|||
|
|||
* Затем проверьте, что вопрос (в подавляющем большинстве - это вопросы) Вам **ясен**. |
|||
* Затем проверьте, что вопрос (в подавляющем большинстве это вопросы) сформулирован **ясно**. |
|||
|
|||
* Во многих случаях вопрос касается решения, которое пользователь придумал сам, но может быть и решение **получше**. Если Вы поймёте проблему и обстоятельства случая, то сможете предложить **альтернативное решение**. |
|||
* Во многих случаях спрашивают о воображаемом решении пользователя, но может быть решение **получше**. Если Вы лучше поймёте проблему и кейс, сможете предложить **альтернативное решение**. |
|||
|
|||
* Ежели вопрос Вам непонятен, запросите больше **деталей**. |
|||
* Если вопрос непонятен, запросите больше **деталей**. |
|||
|
|||
### Воспроизвести проблему |
|||
### Воспроизвести проблему { #reproduce-the-problem } |
|||
|
|||
В большинстве случаев есть что-то связанное с **исходным кодом** вопрошающего. |
|||
В большинстве случаев и вопросов есть что-то связанное с **исходным кодом** автора. |
|||
|
|||
И во многих случаях будет предоставлен только фрагмент этого кода, которого недостаточно для **воспроизведения проблемы**. |
|||
Во многих случаях предоставляют только фрагмент кода, но этого недостаточно, чтобы **воспроизвести проблему**. |
|||
|
|||
* Попросите предоставить <a href="https://stackoverflow.com/help/minimal-reproducible-example" class="external-link" target="_blank">минимальный воспроизводимый пример</a>, который можно **скопировать** и запустить локально дабы увидеть такую же ошибку, или поведение, или лучше понять обстоятельства случая. |
|||
* Попросите предоставить <a href="https://stackoverflow.com/help/minimal-reproducible-example" class="external-link" target="_blank">минимальный воспроизводимый пример</a>, который Вы сможете **скопировать-вставить** и запустить локально, чтобы увидеть ту же ошибку или поведение, или лучше понять их кейс. |
|||
|
|||
* Если на Вас нахлынуло великодушие, то можете попытаться **создать похожий пример** самостоятельно, основываясь только на описании проблемы. Но имейте в виду, что это может занять много времени и, возможно, стоит сначала позадавать вопросы для прояснения проблемы. |
|||
* Если чувствуете себя особенно великодушными, можете попытаться **создать такой пример** сами, основываясь только на описании проблемы. Просто помните, что это может занять много времени, и, возможно, сначала лучше попросить уточнить проблему. |
|||
|
|||
### Предложить решение |
|||
### Предложить решение { #suggest-solutions } |
|||
|
|||
* После того как Вы поняли вопрос, Вы можете дать **ответ**. |
|||
* После того как Вы поняли вопрос, Вы можете дать возможный **ответ**. |
|||
|
|||
* Следует понять **основную проблему и обстоятельства случая**, потому что может быть решение лучше, чем то, которое пытались реализовать. |
|||
* Во многих случаях лучше понять **исходную проблему или кейс**, потому что может существовать способ решить её лучше, чем то, что пытаются сделать. |
|||
|
|||
### Попросить закрыть проблему |
|||
### Попросить закрыть { #ask-to-close } |
|||
|
|||
Если Вам ответили, высоки шансы, что Вам удалось решить проблему, поздравляю, **Вы - герой**! 🦸 |
|||
Если Вам ответили, велика вероятность, что Вы решили их проблему, поздравляю, **Вы — герой**! 🦸 |
|||
|
|||
* В таком случае, если вопрос решён, попросите **закрыть проблему**. |
|||
* Теперь, если проблема решена, можно попросить их: |
|||
* В GitHub Discussions: пометить комментарий как **answer** (ответ). |
|||
* В GitHub Issues: **закрыть** Issue. |
|||
|
|||
## Отслеживать репозиторий на GitHub |
|||
## Отслеживать репозиторий на GitHub { #watch-the-github-repository } |
|||
|
|||
Вы можете "отслеживать" FastAPI на GitHub (кликните по кнопке "watch" наверху справа): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. 👀 |
|||
Вы можете "отслеживать" FastAPI на GitHub (кликнув по кнопке "watch" наверху справа): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. 👀 |
|||
|
|||
Если Вы выберете "Watching" вместо "Releases only", то будете получать уведомления когда кто-либо попросит о помощи с решением его проблемы. |
|||
Если Вы выберете "Watching" вместо "Releases only", то будете получать уведомления, когда кто-либо создаёт новый вопрос или Issue. Вы также можете указать, что хотите получать уведомления только о новых Issues, или обсуждениях, или пулл-реквестах и т.д. |
|||
|
|||
Тогда Вы можете попробовать решить эту проблему. |
|||
Тогда Вы можете попробовать помочь им с решением этих вопросов. |
|||
|
|||
## Запросить помощь с решением проблемы |
|||
## Задать вопросы { #ask-questions } |
|||
|
|||
Вы можете <a href="https://github.com/fastapi/fastapi/issues/new/choose" class="external-link" target="_blank">создать новый запрос с просьбой о помощи</a> в репозитории на GitHub, например: |
|||
Вы можете <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">создать новый вопрос</a> в репозитории GitHub, например: |
|||
|
|||
* Задать **вопрос** или попросить помощи в решении **проблемы**. |
|||
* Предложить новое **улучшение**. |
|||
* Задать **вопрос** или спросить о **проблеме**. |
|||
* Предложить новую **возможность**. |
|||
|
|||
**Заметка**: Если Вы создаёте подобные запросы, то я попрошу Вас также оказывать аналогичную помощь другим. 😉 |
|||
**Заметка**: если Вы это сделаете, то я попрошу Вас также помогать другим. 😉 |
|||
|
|||
## Проверять пул-реквесты |
|||
## Проверять пулл-реквесты { #review-pull-requests } |
|||
|
|||
Вы можете помочь мне проверять пул-реквесты других участников. |
|||
Вы можете помочь мне проверять пулл-реквесты других участников. |
|||
|
|||
И повторюсь, постарайтесь быть доброжелательным. 🤗 |
|||
И, снова, постарайтесь быть доброжелательными. 🤗 |
|||
|
|||
--- |
|||
|
|||
О том, что нужно иметь в виду при проверке пул-реквестов: |
|||
О том, что нужно иметь в виду и как проверять пулл-реквест: |
|||
|
|||
### Понять проблему |
|||
### Понять проблему { #understand-the-problem } |
|||
|
|||
* Во-первых, убедитесь, что **поняли проблему**, которую пул-реквест пытается решить. Для этого может потребоваться продолжительное обсуждение. |
|||
* Во-первых, убедитесь, что **поняли проблему**, которую пулл-реквест пытается решить. Возможно, это обсуждалось более подробно в GitHub Discussion или Issue. |
|||
|
|||
* Также есть вероятность, что пул-реквест не актуален, так как проблему можно решить **другим путём**. В таком случае Вы можете указать на этот факт. |
|||
* Также есть вероятность, что пулл-реквест не нужен, так как проблему можно решить **другим путём**. Тогда Вы можете предложить или спросить об этом. |
|||
|
|||
### Не переживайте о стиле |
|||
### Не переживайте о стиле { #dont-worry-about-style } |
|||
|
|||
* Не стоит слишком беспокоиться о таких вещах, как стиль сообщений в коммитах или количество коммитов. При слиянии пул-реквеста с основной веткой, я буду сжимать и настраивать всё вручную. |
|||
* Не стоит слишком беспокоиться о таких вещах, как стиль сообщений в коммитах — при слиянии я выполню squash и настрою коммит вручную. |
|||
|
|||
* Также не беспокойтесь о правилах стиля, для проверки сего есть автоматизированные инструменты. |
|||
* Также не беспокойтесь о правилах стиля, это уже проверяют автоматизированные инструменты. |
|||
|
|||
И если всё же потребуется какой-то другой стиль, я попрошу Вас об этом напрямую или добавлю сам коммиты с необходимыми изменениями. |
|||
Если будет нужна какая-то другая стилистика или единообразие, я попрошу об этом напрямую или добавлю поверх свои коммиты с нужными изменениями. |
|||
|
|||
### Проверить код |
|||
### Проверить код { #check-the-code } |
|||
|
|||
* Проверьте и прочитайте код, посмотрите, какой он имеет смысл, **запустите его локально** и посмотрите, действительно ли он решает поставленную задачу. |
|||
* Проверьте и прочитайте код, посмотрите, логичен ли он, **запустите его локально** и проверьте, действительно ли он решает проблему. |
|||
|
|||
* Затем, используя **комментарий**, сообщите, что Вы сделали проверку, тогда я буду знать, что Вы действительно проверили код. |
|||
* Затем оставьте **комментарий**, что Вы это сделали, так я пойму, что Вы действительно проверили код. |
|||
|
|||
/// info | Информация |
|||
|
|||
К сожалению, я не могу так просто доверять пул-реквестам, у которых уже есть несколько одобрений. |
|||
К сожалению, я не могу просто доверять PR-ам только потому, что у них есть несколько одобрений. |
|||
|
|||
Бывали случаи, что пул-реквесты имели 3, 5 или больше одобрений, вероятно из-за привлекательного описания, но когда я проверял эти пул-реквесты, они оказывались сломаны, содержали ошибки или вовсе не решали проблему, которую, как они утверждали, должны были решить. 😅 |
|||
Несколько раз было так, что у PR-ов было 3, 5 или больше одобрений, вероятно из-за привлекательного описания, но когда я их проверял, они оказывались сломанными, содержали баги или вовсе не решали заявленную проблему. 😅 |
|||
|
|||
Потому это действительно важно - проверять и запускать код, и комментарием уведомлять меня, что Вы проделали эти действия. 🤓 |
|||
Поэтому очень важно действительно прочитать и запустить код и сообщить мне об этом в комментарии. 🤓 |
|||
|
|||
/// |
|||
|
|||
* Если Вы считаете, что пул-реквест можно упростить, то можете попросить об этом, но не нужно быть слишком придирчивым, может быть много субъективных точек зрения (и у меня тоже будет своя 🙈), поэтому будет лучше, если Вы сосредоточитесь на фундаментальных вещах. |
|||
* Если PR можно упростить, Вы можете попросить об этом, но не нужно быть слишком придирчивым — может быть много субъективных мнений (и у меня тоже 🙈), поэтому лучше сосредоточиться на фундаментальных вещах. |
|||
|
|||
### Тестировать |
|||
### Тестировать { #tests } |
|||
|
|||
* Помогите мне проверить, что у пул-реквеста есть **тесты**. |
|||
* Помогите мне проверить, что у PR есть **тесты**. |
|||
|
|||
* Проверьте, что тесты **падали** до пул-реквеста. 🚨 |
|||
* Проверьте, что тесты **падают** до PR. 🚨 |
|||
|
|||
* Затем проверьте, что тесты **не валятся** после пул-реквеста. ✅ |
|||
* Затем проверьте, что тесты **проходят** после PR. ✅ |
|||
|
|||
* Многие пул-реквесты не имеют тестов, Вы можете **напомнить** о необходимости добавления тестов или даже **предложить** какие-либо свои тесты. Это одна из тех вещей, которые отнимают много времени и Вы можете помочь с этим. |
|||
* Многие PR не имеют тестов — Вы можете **напомнить** добавить тесты или даже **предложить** некоторые тесты сами. Это одна из самых трудозатратных частей, и здесь Вы можете очень помочь. |
|||
|
|||
* Затем добавьте комментарий, что Вы испробовали в ходе проверки. Таким образом я буду знать, как Вы произвели проверку. 🤓 |
|||
* Затем добавьте комментарий, что Вы попробовали, чтобы я знал, что Вы это проверили. 🤓 |
|||
|
|||
## Создать пул-реквест |
|||
## Создать пулл-реквест { #create-a-pull-request } |
|||
|
|||
Вы можете [сделать вклад](contributing.md){.internal-link target=_blank} в код фреймворка используя пул-реквесты, например: |
|||
Вы можете [сделать вклад](contributing.md){.internal-link target=_blank} в исходный код пулл-реквестами, например: |
|||
|
|||
* Исправить опечатку, которую Вы нашли в документации. |
|||
* Поделиться статьёй, видео или подкастом о FastAPI, которые Вы создали или нашли <a href="https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml" class="external-link" target="_blank">изменив этот файл</a>. |
|||
* Убедитесь, что Вы добавили свою ссылку в начало соответствующего раздела. |
|||
* Помочь с [переводом документации](contributing.md#_8){.internal-link target=_blank} на Ваш язык. |
|||
* Вы также можете проверять переводы сделанные другими. |
|||
* Исправить опечатку, найденную в документации. |
|||
* Поделиться статьёй, видео или подкастом о FastAPI, которые Вы создали или нашли, <a href="https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml" class="external-link" target="_blank">изменив этот файл</a>. |
|||
* Убедитесь, что добавили свою ссылку в начало соответствующего раздела. |
|||
* Помочь с [переводом документации](contributing.md#translations){.internal-link target=_blank} на Ваш язык. |
|||
* Вы также можете проверять переводы, сделанные другими. |
|||
* Предложить новые разделы документации. |
|||
* Исправить существующуе проблемы/баги. |
|||
* Исправить существующую проблему/баг. |
|||
* Убедитесь, что добавили тесты. |
|||
* Добавить новую возможность. |
|||
* Убедитесь, что добавили тесты. |
|||
* Убедитесь, что добавили документацию, если она необходима. |
|||
* Убедитесь, что добавили документацию, если это уместно. |
|||
|
|||
## Помочь поддерживать FastAPI |
|||
## Помочь поддерживать FastAPI { #help-maintain-fastapi } |
|||
|
|||
Помогите мне поддерживать **FastAPI**! 🤓 |
|||
|
|||
Предстоит ещё много работы и, по большей части, **ВЫ** можете её сделать. |
|||
Предстоит ещё много работы, и, по большей части, **ВЫ** можете её сделать. |
|||
|
|||
Основные задачи, которые Вы можете выполнить прямо сейчас: |
|||
|
|||
* [Помочь другим с их проблемами на GitHub](#github_1){.internal-link target=_blank} (смотрите вышестоящую секцию). |
|||
* [Проверить пул-реквесты](#-){.internal-link target=_blank} (смотрите вышестоящую секцию). |
|||
* [Помочь другим с вопросами на GitHub](#help-others-with-questions-in-github){.internal-link target=_blank} (смотрите секцию выше). |
|||
* [Проверять пулл-реквесты](#review-pull-requests){.internal-link target=_blank} (смотрите секцию выше). |
|||
|
|||
Эти две задачи **отнимают больше всего времени**. Это основная работа по поддержке FastAPI. |
|||
Именно эти две задачи **забирают больше всего времени**. Это основная работа по поддержке FastAPI. |
|||
|
|||
Если Вы можете помочь мне с этим, **Вы помогаете поддерживать FastAPI** и следить за тем, чтобы он продолжал **развиваться быстрее и лучше**. 🚀 |
|||
Если Вы можете помочь мне с этим, **Вы помогаете поддерживать FastAPI** и делаете так, чтобы он продолжал **развиваться быстрее и лучше**. 🚀 |
|||
|
|||
## Подключиться к чату |
|||
## Подключиться к чату { #join-the-chat } |
|||
|
|||
Подключайтесь к 👥 <a href="https://discord.gg/VQjSZaeJmf" class="external-link" target="_blank"> чату в Discord</a> 👥 и общайтесь с другими участниками сообщества FastAPI. |
|||
Подключайтесь к 👥 <a href="https://discord.gg/VQjSZaeJmf" class="external-link" target="_blank">серверу чата в Discord</a> 👥 и общайтесь с другими участниками сообщества FastAPI. |
|||
|
|||
/// tip | Подсказка |
|||
|
|||
Вопросы по проблемам с фреймворком лучше задавать в <a href="https://github.com/fastapi/fastapi/issues/new/choose" class="external-link" target="_blank">GitHub issues</a>, так больше шансов, что Вы получите помощь от [Экспертов FastAPI](fastapi-people.md#_3){.internal-link target=_blank}. |
|||
По вопросам — задавайте их в <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">GitHub Discussions</a>, так гораздо выше шанс, что Вы получите помощь от [Экспертов FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}. |
|||
|
|||
Используйте этот чат только для бесед на отвлечённые темы. |
|||
Используйте чат только для прочих общих бесед. |
|||
|
|||
/// |
|||
|
|||
### Не использовать чаты для вопросов |
|||
|
|||
Имейте в виду, что чаты позволяют больше "свободного общения", потому там легко задавать вопросы, которые слишком общие и на которые труднее ответить, так что Вы можете не получить нужные Вам ответы. |
|||
|
|||
В разделе "проблемы" на GitHub, есть шаблон, который поможет Вам написать вопрос правильно, чтобы Вам было легче получить хороший ответ или даже решить проблему самостоятельно, прежде чем Вы зададите вопрос. В GitHub я могу быть уверен, что всегда отвечаю на всё, даже если это займет какое-то время. И я не могу сделать то же самое в чатах. 😅 |
|||
|
|||
Кроме того, общение в чатах не так легкодоступно для поиска, как в GitHub, потому вопросы и ответы могут потеряться среди другого общения. И только проблемы решаемые на GitHub учитываются в получении лычки [Эксперт FastAPI](fastapi-people.md#_3){.internal-link target=_blank}, так что весьма вероятно, что Вы получите больше внимания на GitHub. |
|||
|
|||
С другой стороны, в чатах тысячи пользователей, а значит есть большие шансы в любое время найти там кого-то, с кем можно поговорить. 😄 |
|||
|
|||
## Спонсировать автора |
|||
|
|||
Вы также можете оказать мне финансовую поддержку посредством <a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">спонсорства через GitHub</a>. |
|||
### Не используйте чат для вопросов { #dont-use-the-chat-for-questions } |
|||
|
|||
Там можно просто купить мне кофе ☕️ в знак благодарности. 😄 |
|||
Имейте в виду, что в чатах, благодаря "свободному общению", легко задать вопросы, которые слишком общие и на которые сложнее ответить, поэтому Вы можете не получить ответы. |
|||
|
|||
А ещё Вы можете стать Серебряным или Золотым спонсором для FastAPI. 🏅🎉 |
|||
На GitHub шаблон поможет Вам правильно сформулировать вопрос, чтобы Вам было легче получить хороший ответ или даже решить проблему самостоятельно ещё до того, как спросите. И на GitHub я могу следить за тем, чтобы всегда отвечать на всё, даже если это занимает время. А с чатами я не могу сделать этого лично. 😅 |
|||
|
|||
## Спонсировать инструменты, на которых зиждется мощь FastAPI |
|||
Кроме того, переписка в чатах хуже ищется, чем на GitHub, поэтому вопросы и ответы могут теряться среди остальных сообщений. И только те, что на GitHub, учитываются для получения лычки [Эксперт FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}, так что вероятнее всего Вы получите больше внимания именно на GitHub. |
|||
|
|||
Как Вы могли заметить в документации, FastAPI опирается на плечи титанов: Starlette и Pydantic. |
|||
С другой стороны, в чатах тысячи пользователей, так что почти всегда есть шанс найти там кого-то для разговора. 😄 |
|||
|
|||
Им тоже можно оказать спонсорскую поддержку: |
|||
## Спонсировать автора { #sponsor-the-author } |
|||
|
|||
* <a href="https://github.com/sponsors/samuelcolvin" class="external-link" target="_blank">Samuel Colvin (Pydantic)</a> |
|||
* <a href="https://github.com/sponsors/encode" class="external-link" target="_blank">Encode (Starlette, Uvicorn)</a> |
|||
Если Ваш **продукт/компания** зависят от **FastAPI** или связаны с ним и Вы хотите донести до пользователей информацию о себе, Вы можете спонсировать автора (меня) через <a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub Sponsors</a>. В зависимости от уровня поддержки Вы можете получить дополнительные бонусы, например, бейдж в документации. 🎁 |
|||
|
|||
--- |
|||
|
|||
Благодарствую! 🚀 |
|||
Спасибо! 🚀 |
|||
|
@ -1,84 +1,28 @@ |
|||
# Генераторы проектов - Шаблоны |
|||
|
|||
Чтобы начать работу быстрее, Вы можете использовать "генераторы проектов", в которые включены множество начальных настроек для функций безопасности, баз данных и некоторые <dfn title="также известные как маршруты, URLы, ручки, ">эндпоинты</dfn> API. |
|||
|
|||
В генераторе проектов всегда будут предустановлены какие-то настройки, которые Вам следует обновить и подогнать под свои нужды, но это может быть хорошей отправной точкой для Вашего проекта. |
|||
|
|||
## Full Stack FastAPI PostgreSQL |
|||
|
|||
GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-fastapi-postgresql</a> |
|||
|
|||
### Full Stack FastAPI PostgreSQL - Особенности |
|||
|
|||
* Полностью интегрирован с **Docker** (основан на Docker). |
|||
* Развёртывается в режиме Docker Swarm. |
|||
* Интегрирован с **Docker Compose** и оптимизирован для локальной разработки. |
|||
* **Готовый к реальной работе** веб-сервер Python использующий Uvicorn и Gunicorn. |
|||
* Бэкенд построен на фреймворке <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">**FastAPI**</a>: |
|||
* **Быстрый**: Высокопроизводительный, на уровне **NodeJS** и **Go** (благодаря Starlette и Pydantic). |
|||
* **Интуитивно понятный**: Отличная поддержка редактора. <dfn title="также известное как автозаполнение, интеллектуальность, автозавершение">Автодополнение кода</dfn> везде. Меньше времени на отладку. |
|||
* **Простой**: Разработан так, чтоб быть простым в использовании и изучении. Меньше времени на чтение документации. |
|||
* **Лаконичный**: Минимизировано повторение кода. Каждый объявленный параметр определяет несколько функций. |
|||
* **Надёжный**: Получите готовый к работе код. С автоматической интерактивной документацией. |
|||
* **Стандартизированный**: Основан на открытых стандартах API (<a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> и <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>) и полностью совместим с ними. |
|||
* <a href="https://fastapi.tiangolo.com/features/" class="external-link" target="_blank">**Множество других возможностей**</a> включая автоматическую проверку и сериализацию данных, интерактивную документацию, аутентификацию с помощью OAuth2 JWT-токенов и т.д. |
|||
* **Безопасное хранение паролей**, которые хэшируются по умолчанию. |
|||
* Аутентификация посредством **JWT-токенов**. |
|||
* <dfn title="Python-объекты связанные с базами данных">Модели</dfn> **SQLAlchemy** (независящие от расширений Flask, а значит могут быть непосредственно использованы процессами Celery). |
|||
* Базовая модель пользователя (измените или удалите её по необходимости). |
|||
* **Alembic** для организации миграций. |
|||
* **CORS** (Совместное использование ресурсов из разных источников). |
|||
* **Celery**, процессы которого могут выборочно импортировать и использовать модели и код из остальной части бэкенда. |
|||
* Тесты, на основе **Pytest**, интегрированные в Docker, чтобы Вы могли полностью проверить Ваше API, независимо от базы данных. Так как тесты запускаются в Docker, для них может создаваться новое хранилище данных каждый раз (Вы можете, по своему желанию, использовать ElasticSearch, MongoDB, CouchDB или другую СУБД, только лишь для проверки - будет ли Ваше API работать с этим хранилищем). |
|||
* Простая интеграция Python с **Jupyter Kernels** для разработки удалённо или в Docker с расширениями похожими на Atom Hydrogen или Visual Studio Code Jupyter. |
|||
* Фронтенд построен на фреймворке **Vue**: |
|||
* Сгенерирован с помощью Vue CLI. |
|||
* Поддерживает **аутентификацию с помощью JWT-токенов**. |
|||
* Страница логина. |
|||
* Перенаправление на страницу главной панели мониторинга после логина. |
|||
* Главная страница мониторинга с возможностью создания и изменения пользователей. |
|||
* Пользователь может изменять свои данные. |
|||
* **Vuex**. |
|||
* **Vue-router**. |
|||
* **Vuetify** для конструирования красивых компонентов страниц. |
|||
* **TypeScript**. |
|||
* Сервер Docker основан на **Nginx** (настроен для удобной работы с Vue-router). |
|||
* Многоступенчатая сборка Docker, то есть Вам не нужно сохранять или коммитить скомпилированный код. |
|||
* Тесты фронтенда запускаются во время сборки (можно отключить). |
|||
* Сделан настолько модульно, насколько возможно, поэтому работает "из коробки", но Вы можете повторно сгенерировать фронтенд с помощью Vue CLI или создать то, что Вам нужно и повторно использовать то, что захотите. |
|||
* **PGAdmin** для СУБД PostgreSQL, которые легко можно заменить на PHPMyAdmin и MySQL. |
|||
* **Flower** для отслеживания работы Celery. |
|||
* Балансировка нагрузки между фронтендом и бэкендом с помощью **Traefik**, а значит, Вы можете расположить их на одном домене, разделив url-пути, так как они обслуживаются разными контейнерами. |
|||
* Интеграция с Traefik включает автоматическую генерацию сертификатов Let's Encrypt для поддержки протокола **HTTPS**. |
|||
* GitLab **CI** (непрерывная интеграция), которая включает тестирование фронтенда и бэкенда. |
|||
|
|||
## Full Stack FastAPI Couchbase |
|||
|
|||
GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-couchbase" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-fastapi-couchbase</a> |
|||
|
|||
⚠️ **ПРЕДУПРЕЖДЕНИЕ** ⚠️ |
|||
|
|||
Если Вы начинаете новый проект, ознакомьтесь с представленными здесь альтернативами. |
|||
|
|||
Например, генератор проектов <a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" class="external-link" target="_blank">Full Stack FastAPI PostgreSQL</a> может быть более подходящей альтернативой, так как он активно поддерживается и используется. И он включает в себя все новые возможности и улучшения. |
|||
|
|||
Но никто не запрещает Вам использовать генератор с СУБД Couchbase, возможно, он всё ещё работает нормально. Или у Вас уже есть проект, созданный с помощью этого генератора ранее, и Вы, вероятно, уже обновили его в соответствии со своими потребностями. |
|||
|
|||
Вы можете прочитать о нём больше в документации соответствующего репозитория. |
|||
|
|||
## Full Stack FastAPI MongoDB |
|||
|
|||
...может быть когда-нибудь появится, в зависимости от наличия у меня свободного времени и прочих факторов. 😅 🎉 |
|||
|
|||
## Модели машинного обучения на основе spaCy и FastAPI |
|||
|
|||
GitHub: <a href="https://github.com/microsoft/cookiecutter-spacy-fastapi" class="external-link" target="_blank">https://github.com/microsoft/cookiecutter-spacy-fastapi</a> |
|||
|
|||
### Модели машинного обучения на основе spaCy и FastAPI - Особенности |
|||
|
|||
* Интеграция с моделями **spaCy** NER. |
|||
* Встроенный формат запросов к **когнитивному поиску Azure**. |
|||
* **Готовый к реальной работе** веб-сервер Python использующий Uvicorn и Gunicorn. |
|||
* Встроенное развёртывание на основе **Azure DevOps** Kubernetes (AKS) CI/CD. |
|||
* **Многоязычность**. Лёгкий выбор одного из встроенных в spaCy языков во время настройки проекта. |
|||
* **Легко подключить** модели из других фреймворков (Pytorch, Tensorflow) не ограничиваясь spaCy. |
|||
# Шаблон Full Stack FastAPI { #full-stack-fastapi-template } |
|||
|
|||
Шаблоны, хотя обычно поставляются с определённой конфигурацией, спроектированы так, чтобы быть гибкими и настраиваемыми. Это позволяет вам изменять их и адаптировать под требования вашего проекта, что делает их отличной отправной точкой. 🏁 |
|||
|
|||
Вы можете использовать этот шаблон для старта: в нём уже сделана значительная часть начальной настройки, безопасность, база данных и несколько эндпоинтов API. |
|||
|
|||
Репозиторий GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-template" class="external-link" target="_blank">Full Stack FastAPI Template</a> |
|||
|
|||
## Шаблон Full Stack FastAPI — Технологический стек и возможности { #full-stack-fastapi-template-technology-stack-and-features } |
|||
|
|||
- ⚡ [**FastAPI**](https://fastapi.tiangolo.com/ru) для бэкенд‑API на Python. |
|||
- 🧰 [SQLModel](https://sqlmodel.tiangolo.com) для взаимодействия с SQL‑базой данных на Python (ORM). |
|||
- 🔍 [Pydantic](https://docs.pydantic.dev), используется FastAPI, для валидации данных и управления настройками. |
|||
- 💾 [PostgreSQL](https://www.postgresql.org) в качестве SQL‑базы данных. |
|||
- 🚀 [React](https://react.dev) для фронтенда. |
|||
- 💃 Используются TypeScript, хуки, [Vite](https://vitejs.dev) и другие части современного фронтенд‑стека. |
|||
- 🎨 [Chakra UI](https://chakra-ui.com) для компонентов фронтенда. |
|||
- 🤖 Автоматически сгенерированный фронтенд‑клиент. |
|||
- 🧪 [Playwright](https://playwright.dev) для End‑to‑End тестирования. |
|||
- 🦇 Поддержка тёмной темы. |
|||
- 🐋 [Docker Compose](https://www.docker.com) для разработки и продакшна. |
|||
- 🔒 Безопасное хэширование паролей по умолчанию. |
|||
- 🔑 Аутентификация по JWT‑токенам. |
|||
- 📫 Восстановление пароля по электронной почте. |
|||
- ✅ Тесты с [Pytest](https://pytest.org). |
|||
- 📞 [Traefik](https://traefik.io) в роли обратного прокси / балансировщика нагрузки. |
|||
- 🚢 Инструкции по развёртыванию с использованием Docker Compose, включая настройку фронтенд‑прокси Traefik для автоматического получения сертификатов HTTPS. |
|||
- 🏭 CI (continuous integration) и CD (continuous deployment) на основе GitHub Actions. |
|||
|
@ -1,84 +1,84 @@ |
|||
# Фоновые задачи |
|||
# Фоновые задачи { #background-tasks } |
|||
|
|||
Вы можете создавать фоновые задачи, которые будут выполнятся *после* возвращения ответа сервером. |
|||
Вы можете создавать фоновые задачи, которые будут выполняться после возврата ответа. |
|||
|
|||
Это может быть полезно для функций, которые должны выполниться после получения запроса, но ожидание их выполнения необязательно для пользователя. |
|||
Это полезно для операций, которые должны произойти после HTTP-запроса, но клиенту не обязательно ждать их завершения, чтобы получить ответ. |
|||
|
|||
К примеру: |
|||
Например: |
|||
|
|||
* Отправка писем на почту после выполнения каких-либо действий: |
|||
* Т.к. соединение с почтовым сервером и отправка письма идут достаточно "долго" (несколько секунд), вы можете отправить ответ пользователю, а отправку письма выполнить в фоне. |
|||
* Уведомления по электронной почте, отправляемые после выполнения действия: |
|||
* Так как подключение к почтовому серверу и отправка письма обычно «медленные» (несколько секунд), вы можете сразу вернуть ответ, а отправку уведомления выполнить в фоне. |
|||
* Обработка данных: |
|||
* К примеру, если вы получаете файл, который должен пройти через медленный процесс, вы можете отправить ответ "Accepted" (HTTP 202) и отправить работу с файлом в фон. |
|||
* Например, если вы получаете файл, который должен пройти через медленный процесс, вы можете вернуть ответ «Accepted» (HTTP 202) и обработать файл в фоне. |
|||
|
|||
## Использование класса `BackgroundTasks` |
|||
## Использование `BackgroundTasks` { #using-backgroundtasks } |
|||
|
|||
Сначала импортируйте `BackgroundTasks`, потом добавьте в функцию параметр с типом `BackgroundTasks`: |
|||
Сначала импортируйте `BackgroundTasks` и объявите параметр в вашей функции‑обработчике пути с типом `BackgroundTasks`: |
|||
|
|||
{* ../../docs_src/background_tasks/tutorial001.py hl[1,13] *} |
|||
|
|||
**FastAPI** создаст объект класса `BackgroundTasks` для вас и запишет его в параметр. |
|||
**FastAPI** создаст объект типа `BackgroundTasks` для вас и передаст его через этот параметр. |
|||
|
|||
## Создание функции для фоновой задачи |
|||
## Создание функции для фоновой задачи { #create-a-task-function } |
|||
|
|||
Создайте функцию, которую хотите запустить в фоне. |
|||
Создайте функцию, которую нужно запустить как фоновую задачу. |
|||
|
|||
Это совершенно обычная функция, которая может принимать параметры. |
|||
Это обычная функция, которая может принимать параметры. |
|||
|
|||
Она может быть как асинхронной `async def`, так и обычной `def` функцией, **FastAPI** знает, как правильно ее выполнить. |
|||
Это может быть как `async def`, так и обычная функция `def`, **FastAPI** знает, как корректно её выполнить. |
|||
|
|||
В нашем примере фоновая задача будет вести запись в файл (симулируя отправку письма). |
|||
В этом случае функция задачи будет записывать данные в файл (имитируя отправку письма). |
|||
|
|||
Так как операция записи не использует `async` и `await`, мы определим ее как обычную `def`: |
|||
Так как операция записи не использует `async` и `await`, мы определим функцию как обычную `def`: |
|||
|
|||
{* ../../docs_src/background_tasks/tutorial001.py hl[6:9] *} |
|||
|
|||
## Добавление фоновой задачи |
|||
## Добавление фоновой задачи { #add-the-background-task } |
|||
|
|||
Внутри функции вызовите метод `.add_task()` у объекта *background tasks* и передайте ему функцию, которую хотите выполнить в фоне: |
|||
Внутри вашей функции‑обработчика пути передайте функцию задачи объекту фоновых задач методом `.add_task()`: |
|||
|
|||
{* ../../docs_src/background_tasks/tutorial001.py hl[14] *} |
|||
|
|||
`.add_task()` принимает следующие аргументы: |
|||
|
|||
* Функцию, которая будет выполнена в фоне (`write_notification`). Обратите внимание, что передается объект функции, без скобок. |
|||
* Любое упорядоченное количество аргументов, которые принимает функция (`email`). |
|||
* Любое количество именованных аргументов, которые принимает функция (`message="some notification"`). |
|||
* Функцию задачи, которую нужно выполнить в фоне (`write_notification`). |
|||
* Последовательность позиционных аргументов, которые должны быть переданы функции задачи, в порядке (`email`). |
|||
* Любые именованные аргументы, которые должны быть переданы функции задачи (`message="some notification"`). |
|||
|
|||
## Встраивание зависимостей |
|||
## Встраивание зависимостей { #dependency-injection } |
|||
|
|||
Класс `BackgroundTasks` также работает с системой встраивания зависимостей, вы можете определить `BackgroundTasks` на разных уровнях: как параметр функции, как завимость, как подзависимость и так далее. |
|||
Использование `BackgroundTasks` также работает с системой встраивания зависимостей, вы можете объявить параметр типа `BackgroundTasks` на нескольких уровнях: в функции‑обработчике пути, в зависимости (dependable), в подзависимости и т. д. |
|||
|
|||
**FastAPI** знает, что нужно сделать в каждом случае и как переиспользовать тот же объект `BackgroundTasks`, так чтобы все фоновые задачи собрались и запустились вместе в фоне: |
|||
**FastAPI** знает, что делать в каждом случае и как переиспользовать один и тот же объект, так чтобы все фоновые задачи были объединены и затем выполнены в фоне: |
|||
|
|||
{* ../../docs_src/background_tasks/tutorial002_py310.py hl[11,13,20,23] *} |
|||
{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *} |
|||
|
|||
В этом примере сообщения будут записаны в `log.txt` *после* того, как ответ сервера был отправлен. |
|||
В этом примере сообщения будут записаны в файл `log.txt` после отправки ответа. |
|||
|
|||
Если бы в запрос был передан query-параметр `q`, он бы первыми записался в `log.txt` фоновой задачей (потому что вызывается в зависимости `get_query`). |
|||
Если в запросе была строка запроса (query), она будет записана в лог фоновой задачей. |
|||
|
|||
После другая фоновая задача, которая была сгенерирована в функции, запишет сообщение из параметра `email`. |
|||
Затем другая фоновая задача, созданная в функции‑обработчике пути, запишет сообщение, используя path‑параметр `email`. |
|||
|
|||
## Технические детали |
|||
## Технические детали { #technical-details } |
|||
|
|||
Класс `BackgroundTasks` основан на <a href="https://www.starlette.io/background/" class="external-link" target="_blank">`starlette.background`</a>. |
|||
Класс `BackgroundTasks` приходит напрямую из <a href="https://www.starlette.io/background/" class="external-link" target="_blank">`starlette.background`</a>. |
|||
|
|||
Он интегрирован в FastAPI, так что вы можете импортировать его прямо из `fastapi` и избежать случайного импорта `BackgroundTask` (без `s` на конце) из `starlette.background`. |
|||
Он импортируется/включается прямо в FastAPI, чтобы вы могли импортировать его из `fastapi` и избежать случайного импорта альтернативного `BackgroundTask` (без `s` на конце) из `starlette.background`. |
|||
|
|||
При использовании `BackgroundTasks` (а не `BackgroundTask`), вам достаточно только определить параметр функции с типом `BackgroundTasks` и **FastAPI** сделает все за вас, также как при использовании объекта `Request`. |
|||
Используя только `BackgroundTasks` (а не `BackgroundTask`), его можно применять как параметр функции‑обработчика пути, и **FastAPI** сделает остальное за вас, как при использовании объекта `Request` напрямую. |
|||
|
|||
Вы все равно можете использовать `BackgroundTask` из `starlette` в FastAPI, но вам придется самостоятельно создавать объект фоновой задачи и вручную обработать `Response` внутри него. |
|||
По‑прежнему можно использовать один `BackgroundTask` в FastAPI, но тогда вам нужно создать объект в своём коде и вернуть Starlette `Response`, включающий его. |
|||
|
|||
Вы можете подробнее изучить его в <a href="https://www.starlette.io/background/" class="external-link" target="_blank">Официальной документации Starlette для BackgroundTasks</a>. |
|||
Подробнее см. в <a href="https://www.starlette.io/background/" class="external-link" target="_blank">официальной документации Starlette по фоновым задачам</a>. |
|||
|
|||
## Предостережение |
|||
## Предостережение { #caveat } |
|||
|
|||
Если вам нужно выполнить тяжелые вычисления в фоне, которым необязательно быть запущенными в одном процессе с приложением **FastAPI** (к примеру, вам не нужны обрабатываемые переменные или вы не хотите делиться памятью процесса и т.д.), вы можете использовать более серьезные инструменты, такие как <a href="https://docs.celeryproject.org" class="external-link" target="_blank">Celery</a>. |
|||
Если вам нужно выполнять тяжелые вычисления в фоне, и при этом они не обязательно должны запускаться тем же процессом (например, вам не нужно делиться памятью, переменными и т. п.), вам могут подойти более мощные инструменты, такие как <a href="https://docs.celeryq.dev" class="external-link" target="_blank">Celery</a>. |
|||
|
|||
Их тяжелее настраивать, также им нужен брокер сообщений наподобие RabbitMQ или Redis, но зато они позволяют вам запускать фоновые задачи в нескольких процессах и даже на нескольких серверах. |
|||
Они обычно требуют более сложной конфигурации, менеджера очереди сообщений/заданий (например, RabbitMQ или Redis), но позволяют запускать фоновые задачи в нескольких процессах и, что особенно важно, на нескольких серверах. |
|||
|
|||
Но если вам нужен доступ к общим переменным и объектам вашего **FastAPI** приложения или вам нужно выполнять простые фоновые задачи (наподобие отправки письма из примера) вы можете просто использовать `BackgroundTasks`. |
|||
Но если вам нужен доступ к переменным и объектам из того же приложения **FastAPI**, или нужно выполнять небольшие фоновые задачи (например, отправку email‑уведомления), вы можете просто использовать `BackgroundTasks`. |
|||
|
|||
## Резюме |
|||
## Резюме { #recap } |
|||
|
|||
Для создания фоновых задач вам необходимо импортировать `BackgroundTasks` и добавить его в функцию, как параметр с типом `BackgroundTasks`. |
|||
Импортируйте и используйте `BackgroundTasks` с параметрами в функциях‑обработчиках пути и зависимостях, чтобы добавлять фоновые задачи. |
|||
|
@ -1,15 +1,15 @@ |
|||
# Глобальные зависимости |
|||
# Глобальные зависимости { #global-dependencies } |
|||
|
|||
Для некоторых типов приложений может потребоваться добавить зависимости ко всему приложению. |
|||
|
|||
Подобно тому, как вы можете [добавлять зависимости через параметр `dependencies` в *декораторах операций пути*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, вы можете добавлять зависимости сразу ко всему `FastAPI` приложению. |
|||
Подобно тому, как вы можете [добавлять `dependencies` (зависимости) в *декораторах операций пути*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, вы можете добавлять зависимости сразу ко всему `FastAPI` приложению. |
|||
|
|||
В этом случае они будут применяться ко всем *операциям пути* в приложении: |
|||
|
|||
{* ../../docs_src/dependencies/tutorial012_an_py39.py hl[16] *} |
|||
|
|||
Все способы [добавления зависимостей в *декораторах операций пути*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} по-прежнему применимы, но в данном случае зависимости применяются ко всем *операциям пути* приложения. |
|||
Все способы [добавления `dependencies` (зависимостей) в *декораторах операций пути*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} по-прежнему применимы, но в данном случае зависимости применяются ко всем *операциям пути* приложения. |
|||
|
|||
## Зависимости для групп *операций пути* |
|||
## Зависимости для групп *операций пути* { #dependencies-for-groups-of-path-operations } |
|||
|
|||
Позднее, читая о том, как структурировать более крупные [приложения, содержащие много файлов](../../tutorial/bigger-applications.md){.internal-link target=_blank}, вы узнаете, как объявить один параметр dependencies для целой группы *операций пути*. |
|||
Позднее, читая о том, как структурировать более крупные [приложения, содержащие много файлов](../../tutorial/bigger-applications.md){.internal-link target=_blank}, вы узнаете, как объявить один параметр `dependencies` для целой группы *операций пути*. |
|||
|
@ -1,83 +1,95 @@ |
|||
# Учебник - Руководство пользователя |
|||
# Учебник - Руководство пользователя { #tutorial-user-guide } |
|||
|
|||
В этом руководстве шаг за шагом показано, как использовать **FastApi** с большинством его функций. |
|||
В этом руководстве шаг за шагом показано, как использовать **FastAPI** с большинством его функций. |
|||
|
|||
Каждый раздел постепенно основывается на предыдущих, но он структурирован по отдельным темам, так что вы можете перейти непосредственно к конкретной теме для решения ваших конкретных потребностей в API. |
|||
Каждый раздел постепенно основывается на предыдущих, но структура разделяет темы, так что вы можете сразу перейти к нужной теме для решения ваших конкретных задач по API. |
|||
|
|||
Он также создан для использования в качестве будущего справочника. |
|||
Он также создан как справочник на будущее, чтобы вы могли вернуться и посмотреть именно то, что вам нужно. |
|||
|
|||
Так что вы можете вернуться и посмотреть именно то, что вам нужно. |
|||
## Запустите код { #run-the-code } |
|||
|
|||
## Запустите код |
|||
Все блоки кода можно копировать и использовать напрямую (это действительно протестированные файлы Python). |
|||
|
|||
Все блоки кода можно копировать и использовать напрямую (на самом деле это проверенные файлы Python). |
|||
|
|||
Чтобы запустить любой из примеров, скопируйте код в файл `main.py` и запустите `uvicorn` с параметрами: |
|||
Чтобы запустить любой из примеров, скопируйте код в файл `main.py` и запустите `fastapi dev` с: |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ uvicorn main:app --reload |
|||
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u> |
|||
|
|||
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting development server 🚀 |
|||
|
|||
Searching for package file structure from directories |
|||
with <font color="#3465A4">__init__.py</font> files |
|||
Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font> |
|||
|
|||
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py |
|||
|
|||
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with |
|||
the following code: |
|||
|
|||
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u> |
|||
|
|||
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font> |
|||
|
|||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font> |
|||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000/docs</u></font> |
|||
|
|||
<span style="background-color:#007166"><font color="#D3D7CF"> tip </font></span> Running in development mode, for production use: |
|||
<b>fastapi run</b> |
|||
|
|||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) |
|||
<span style="color: green;">INFO</span>: Started reloader process [28720] |
|||
<span style="color: green;">INFO</span>: Started server process [28722] |
|||
<span style="color: green;">INFO</span>: Waiting for application startup. |
|||
<span style="color: green;">INFO</span>: Application startup complete. |
|||
Logs: |
|||
|
|||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Will watch for changes in these directories: |
|||
<b>[</b><font color="#4E9A06">'/home/user/code/awesomeapp'</font><b>]</b> |
|||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C |
|||
to quit<b>)</b> |
|||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started reloader process <b>[</b><font color="#34E2E2"><b>383138</b></font><b>]</b> using WatchFiles |
|||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>383153</b></font><b>]</b> |
|||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup. |
|||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete. |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
**НАСТОЯТЕЛЬНО рекомендуется**, чтобы вы написали или скопировали код, отредактировали его и запустили локально. |
|||
**НАСТОЯТЕЛЬНО рекомендуется** написать или скопировать код, отредактировать его и запустить локально. |
|||
|
|||
Использование кода в вашем редакторе — это то, что действительно показывает вам преимущества FastAPI, видя, как мало кода вам нужно написать, все проверки типов, автодополнение и т.д. |
|||
Использование кода в вашем редакторе кода — это то, что действительно показывает преимущества FastAPI: вы увидите, как мало кода нужно написать, все проверки типов, автозавершение и т.д. |
|||
|
|||
--- |
|||
|
|||
## Установка FastAPI |
|||
## Установка FastAPI { #install-fastapi } |
|||
|
|||
Первый шаг — установить FastAPI. |
|||
|
|||
Для руководства вы, возможно, захотите установить его со всеми дополнительными зависимостями и функциями: |
|||
Убедитесь, что вы создали [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его, и затем **установите FastAPI**: |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ pip install "fastapi[all]" |
|||
$ pip install "fastapi[standard]" |
|||
|
|||
---> 100% |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
...это также включает `uvicorn`, который вы можете использовать в качестве сервера, который запускает ваш код. |
|||
|
|||
/// note | Технические детали |
|||
|
|||
Вы также можете установить его по частям. |
|||
/// note | Примечание |
|||
|
|||
Это то, что вы, вероятно, сделаете, когда захотите развернуть свое приложение в рабочей среде: |
|||
При установке с помощью `pip install "fastapi[standard]"` добавляются некоторые стандартные необязательные зависимости по умолчанию, включая `fastapi-cloud-cli`, который позволяет развернуть приложение на <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>. |
|||
|
|||
``` |
|||
pip install fastapi |
|||
``` |
|||
|
|||
Также установите `uvicorn` для работы в качестве сервера: |
|||
|
|||
``` |
|||
pip install "uvicorn[standard]" |
|||
``` |
|||
Если вы не хотите иметь эти необязательные зависимости, установите просто `pip install fastapi`. |
|||
|
|||
И то же самое для каждой из необязательных зависимостей, которые вы хотите использовать. |
|||
Если вы хотите установить стандартные зависимости, но без `fastapi-cloud-cli`, установите `pip install "fastapi[standard-no-fastapi-cloud-cli]"`. |
|||
|
|||
/// |
|||
|
|||
## Продвинутое руководство пользователя |
|||
## Продвинутое руководство пользователя { #advanced-user-guide } |
|||
|
|||
Существует также **Продвинутое руководство пользователя**, которое вы сможете прочитать после руководства **Учебник - Руководство пользователя**. |
|||
Существует также **Продвинутое руководство пользователя**, которое вы сможете прочитать после **Учебник - Руководство пользователя**. |
|||
|
|||
**Продвинутое руководство пользователя** основано на этом, использует те же концепции и учит вас некоторым дополнительным функциям. |
|||
**Продвинутое руководство пользователя** основано на этом, использует те же концепции и обучает некоторым дополнительным функциям. |
|||
|
|||
Но вы должны сначала прочитать **Учебник - Руководство пользователя** (то, что вы читаете прямо сейчас). |
|||
Но сначала вам следует прочитать **Учебник - Руководство пользователя** (то, что вы читаете прямо сейчас). |
|||
|
|||
Он разработан таким образом, что вы можете создать полноценное приложение, используя только **Учебник - Руководство пользователя**, а затем расширить его различными способами, в зависимости от ваших потребностей, используя некоторые дополнительные идеи из **Продвинутого руководства пользователя**. |
|||
Оно спроектировано так, что вы можете создать полноценное приложение, используя только **Учебник - Руководство пользователя**, а затем расширить его различными способами, в зависимости от ваших потребностей, используя дополнительные идеи из **Продвинутого руководства пользователя**. |
|||
|
@ -1,99 +1,105 @@ |
|||
# Данные текущего пользователя |
|||
# Получить текущего пользователя { #get-current-user } |
|||
|
|||
В предыдущей главе система безопасности (основанная на системе внедрения зависимостей) передавала *функции, обрабатывающей эндпоинт,* `токен` в виде `строки`: |
|||
В предыдущей главе система безопасности (основанная на системе внедрения зависимостей) передавала *функции-обработчику пути* `token` типа `str`: |
|||
|
|||
{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *} |
|||
|
|||
Это пока что не слишком нам полезно. Давайте изменим код так, чтобы он возвращал нам данные пользователя, отправившего запрос. |
|||
Но это всё ещё не слишком полезно. |
|||
|
|||
## Создание модели пользователя |
|||
Сделаем так, чтобы она возвращала текущего пользователя. |
|||
|
|||
## Создать модель пользователя { #create-a-user-model } |
|||
|
|||
Сначала создадим Pydantic-модель пользователя. |
|||
|
|||
Точно так же, как мы использовали Pydantic для объявления тел запросов, мы можем использовать его где угодно: |
|||
Точно так же, как мы используем Pydantic для объявления тел запросов, мы можем использовать его где угодно: |
|||
|
|||
{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *} |
|||
|
|||
## Создание зависимости `get_current_user` |
|||
## Создать зависимость `get_current_user` { #create-a-get-current-user-dependency } |
|||
|
|||
Давайте создадим зависимость `get_current_user`. |
|||
|
|||
Помните, что у зависимостей могут быть подзависимости? |
|||
|
|||
`get_current_user` как раз будет иметь подзависимость `oauth2_scheme`, которую мы создали ранее. |
|||
`get_current_user` будет иметь зависимость от того же `oauth2_scheme`, который мы создали ранее. |
|||
|
|||
Аналогично тому, как мы делали это ранее в *обработчике эндпоинта* наша новая зависимость `get_current_user` будет получать `token` в виде `строки` от подзависимости `oauth2_scheme`: |
|||
Аналогично тому, как мы делали ранее прямо в *операции пути*, новая зависимость `get_current_user` получит `token` типа `str` от подзависимости `oauth2_scheme`: |
|||
|
|||
{* ../../docs_src/security/tutorial002_an_py310.py hl[25] *} |
|||
|
|||
## Получение данных пользователя |
|||
## Получить пользователя { #get-the-user } |
|||
|
|||
`get_current_user` будет использовать созданную нами (ненастоящую) служебную функцию, которая принимает токен в виде `строки` и возвращает нашу Pydantic-модель `User`: |
|||
`get_current_user` будет использовать созданную нами (ненастоящую) служебную функцию, которая принимает токен типа `str` и возвращает нашу Pydantic-модель `User`: |
|||
|
|||
{* ../../docs_src/security/tutorial002_an_py310.py hl[19:22,26:27] *} |
|||
|
|||
## Внедрение зависимости текущего пользователя |
|||
## Внедрить текущего пользователя { #inject-the-current-user } |
|||
|
|||
Теперь мы можем использовать тот же `Depends` с нашей зависимостью `get_current_user` в *функции обрабатывающей эндпоинт*: |
|||
Теперь мы можем использовать тот же `Depends` с нашей `get_current_user` в *операции пути*: |
|||
|
|||
{* ../../docs_src/security/tutorial002_an_py310.py hl[31] *} |
|||
|
|||
Обратите внимание, что мы объявляем тип переменной `current_user` как Pydantic-модель `User`. |
|||
Обратите внимание, что мы объявляем тип `current_user` как Pydantic-модель `User`. |
|||
|
|||
Это поможет выполнить внутри функции все проверки автозаполнения и типа. |
|||
Это поможет внутри функции с автозавершением и проверками типов. |
|||
|
|||
/// tip | Подсказка |
|||
Возможно, вы помните, что тело запроса также объявляется с помощью Pydantic-моделей. |
|||
|
|||
В этом месте у **FastAPI** не возникнет проблем, потому что вы используете `Depends`. |
|||
Возможно, вы помните, что тела запросов также объявляются с помощью Pydantic-моделей. |
|||
|
|||
Здесь **FastAPI** не запутается, потому что вы используете `Depends`. |
|||
|
|||
/// |
|||
|
|||
/// check | Заметка |
|||
То, как устроена эта система зависимостей, позволяет нам иметь различные зависимости, которые возвращают модель `User`. |
|||
|
|||
Мы не ограничены наличием только одной зависимости, которая может возвращать данные такого типа. |
|||
То, как устроена эта система зависимостей, позволяет иметь разные зависимости, которые возвращают модель `User`. |
|||
|
|||
Мы не ограничены наличием только одной зависимости, которая может возвращать такой тип данных. |
|||
|
|||
/// |
|||
|
|||
## Другие модели |
|||
## Другие модели { #other-models } |
|||
|
|||
Теперь вы можете получать информацию о текущем пользователе непосредственно в *функции обрабатывающей эндпоинт* и работать с механизмами безопасности на уровне **Внедрения Зависимостей**, используя `Depends`. |
|||
Теперь вы можете получать текущего пользователя напрямую в *функциях-обработчиках пути* и работать с механизмами безопасности на уровне **внедрения зависимостей**, используя `Depends`. |
|||
|
|||
Причем для обеспечения требований безопасности можно использовать любую модель или данные (в данном случае - Pydantic-модель `User`). |
|||
И вы можете использовать любую модель или данные для требований безопасности (в данном случае Pydantic-модель `User`). |
|||
|
|||
Но вы не ограничены использованием какой-то конкретной моделью данных, классом или типом. |
|||
Но вы не ограничены использованием какой-то конкретной модели данных, класса или типа. |
|||
|
|||
Вы хотите использовать в модели `id` и `email`, а `username` вам не нужен? Ну разумеется. Воспользуйтесь тем же инструментарием. |
|||
Хотите, чтобы в модели были `id` и `email`, но не было `username`? Пожалуйста. Можно использовать те же инструменты. |
|||
|
|||
Вам нужны только `строки`? Или только `словари`? Или непосредственно экземпляр модели класса базы данных? Все это работает точно также. |
|||
Хотите просто `str`? Или просто `dict`? Или напрямую экземпляр класса модели базы данных? Всё работает одинаково. |
|||
|
|||
У вас нет пользователей, которые входят в ваше приложение, а только роботы, боты или другие системы, у которых есть только токен доступа? Опять же, все работает одинаково. |
|||
У вас вообще нет пользователей, которые входят в приложение, а есть роботы, боты или другие системы, у которых есть только токен доступа? Снова — всё работает так же. |
|||
|
|||
Просто используйте любую модель, любой класс, любую базу данных, которые нужны для вашего приложения. Система внедрения зависимостей **FastAPI** поможет вам в этом. |
|||
Просто используйте любую модель, любой класс, любую базу данных, которые нужны вашему приложению. Система внедрения зависимостей **FastAPI** поможет вам в этом. |
|||
|
|||
## Размер кода |
|||
## Размер кода { #code-size } |
|||
|
|||
Этот пример может показаться многословным. Следует иметь в виду, что в одном файле мы смешиваем безопасность, модели данных, служебные функции и *эндпоинты*. |
|||
Этот пример может показаться многословным. Имейте в виду, что в одном файле мы смешиваем безопасность, модели данных, служебные функции и *операции пути*. |
|||
|
|||
Но вот ключевой момент: |
|||
Но вот ключевой момент. |
|||
|
|||
Все, что касается безопасности и внедрения зависимостей, пишется один раз. |
|||
Всё, что касается безопасности и внедрения зависимостей, пишется один раз. |
|||
|
|||
И вы можете сделать его настолько сложным, насколько захотите. И все это будет написано только один раз, в одном месте, со всей своей гибкостью. |
|||
И вы можете сделать это настолько сложным, насколько захотите. И всё равно это будет написано только один раз, в одном месте. Со всей гибкостью. |
|||
|
|||
И у вас могут быть тысячи конечных точек (*эндпоинтов*), использующих одну и ту же систему безопасности. |
|||
При этом у вас могут быть тысячи эндпоинтов (*операций пути*), использующих одну и ту же систему безопасности. |
|||
|
|||
И все они (или любая их часть по вашему желанию) могут воспользоваться преимуществами повторного использования этих зависимостей или любых других зависимостей, которые вы создадите. |
|||
|
|||
И все эти тысячи *эндпоинтов* могут составлять всего 3 строки: |
|||
И все эти тысячи *операций пути* могут состоять всего из 3 строк: |
|||
|
|||
{* ../../docs_src/security/tutorial002_an_py310.py hl[30:32] *} |
|||
|
|||
## Резюме |
|||
## Резюме { #recap } |
|||
|
|||
Теперь вы можете получать данные о текущем пользователе непосредственно в своей *функции обработчике эндпоинта*. |
|||
Теперь вы можете получать текущего пользователя прямо в своей *функции-обработчике пути*. |
|||
|
|||
Мы уже на полпути к этому. |
|||
Мы уже на полпути. |
|||
|
|||
Осталось лишь добавить *эндпоинт* для отправки пользователем/клиентом своих `имени пользователя` и `пароля`. |
|||
Нужно лишь добавить *операцию пути*, чтобы пользователь/клиент мог отправить `username` и `password`. |
|||
|
|||
Это будет рассмотрено в следующем разделе. |
|||
Это будет дальше. |
|||
|
Loading…
Reference in new issue