Найти в Дзене
Ржавый код

Понять rust , создав HTTP-сервер

Оглавление

Введение

Rust - высокоэффективный язык программирования, стоящий на самом любимом языке 7 лет подряд. Это связано с тем, что он является производительным, безопасным для памяти и очень гибким. Сегодня мы узнаем о создании HTTP-сервера на rust и изучим несколько концепций языка.

Начнем, убедитесь, что в вашей системе установлен rust, и давайте создадим новый проект.

-2

Построение TCP-сервера

Создание TCP-сервера

Протокол HTTP работает поверх протокола TCP уровня L4 (сетевой уровень). При создании сервера фактически создается сервер TCP, и данные отправляются в формате HTTP, т.е. TCP указывает, как происходит связь, а HTTP указывает схему данных, которые должны быть отправлены по этому соединению.

Откройте `main.rs` в любимой среде IDE и добавьте в нее следующий код:

-3

Давайте перейдем к разбору кода.

-4

Это макрос rust, который сообщает компилятору, что мы можем создать переменные, которые мы можем не использовать. Это упрощает обработку некоторых распространенных ошибок в процессе обучения, но это не следует использовать в производственной кодовой базе.

-5

В основном bind возвращает функцию в перечислении типа Result , которое является способом выразить, что вышеупомянутая функция может или ответить паникой или результатом (здесь `TcpListener`), и мы хотим отказаться продолжать выполнение при ошибке, в другом случае продолжить программу.

Это имеет смысл использовать, если возникновение исключения может привести к остановке программы и она не сможет продолжать выполнение дальше, есть лучшие способы обработки такого исключения.

-6

В имени функции `println` есть восклицательный знак, потому что она не является функцией и является макросом.

-7

Метод `incoming()`, возвращает итератор потоков (в частности, потоков с типом, определяемым, например, `TcpStream`. Один поток представляет открытое соединение между клиентом и сервером, так что здесь мы в основном обходим по каждому соединению через цикл `for`.

Это может показаться тривиальным для наивного разработчика, но опытный человек может знать, что для обработки новых соединений в большинстве языков потребуется логика, управляемая событиями, что технически происходит и здесь, но это ленивый итератор, который автоматически вызывает следующую последовательность в цикле for, упрощая кодирование.

-8

Поток переменных цикла возвращает `Result`, который необходимо развернуть. (Это не элегантный способ справиться с этим, так как один сбой соединения тут, разрушит все приложение, что не должно произойти продакшине).

Кроме того, обратите внимание, что имя переменного потока совпадает с именем потока переменной цикла, который называется затенением в rust. Это также присутствует в других языках, как javascript.

Протестируем код, выполнив запрос:

-9

Вы, вероятно, должны получить что-то вроде
`Connection reset by peer`
Это потому, что мы ничего не делаем с соединением.

Создание обработчика соединений

Создание функции с именем `handle_connection` для данных потока:

-10

О этой функции много можно рассказать, во-первых, ключевое слово `mut` сообщает rust, что `handle_connection` внесет изменения в поток (записав в него, чего мы сейчас не делаем).

Во второй строке мы создаем новый буфер с изменяемой ссылкой на тот же самый поток, то есть это ссылка кучи на тот же самый объект потока. (Больше пустяков дальше)

У нас есть некоторые простые буферные операции перед печатью самого вектора с помощью `{:#?}` это основной способ распечатать вектор в rust, вы также можете использовать `{:?}`, который распечатает все значения в одной строке.

Использование обработчика для потоков соединений

-11

Одно важное примечание - Объект потока теперь принадлежит функции `handle_connection`, что означает, что на него больше нельзя ссылаться в цикле `for`. Если просто попытаться добавить `handle_connection(stream);` второй раз это даст вам ошибку во времени компиляции, указывающую, что поток переменных перемещен. Это очень мощный функционал rust, поскольку он упрощает очистку памяти.

Создание HTTP-соединения

Как мы узнали, HTTP - это просто способ определения структуры данных, передаваемых по TCP-соединению. Для получения дополнительной информации см. полное описание в разделе «Request For Comments».

Создание статуса ответа

Если бы вы сделали запрос с URL на локальном хосте (или открыли в браузере), вы бы не получили ответ, потому что мы фактически не отвечаем клиенту, вызывающему наш сервер.

Добавим это после `handle_connection` функции:

-12

Это стандартные метаданные успеха, здесь сервер сообщает клиенту, что он получил информацию, отправленную клиентом, и все в порядке.

Обратите внимание, что\r\n присутствует в переменной ответа два раза, это стандартный разделитель строк, определенный в протоколе, часто называемый CRLF.

  • CR - возврат каретки (`\r`)
  • LF - переход на новую строку (`\n`)

Давайте отправим html

Создайте файл с именем `response.html`. Создайте его в корне приложения, а не внутри `src/`.

-13

Замените последние 2 строки в функции `handle_connection` на эти:

-14

`fs` - модуль, используемый для работы с файловой системой в rust.

Мы используем `format!` добавляя содержимое файла в качестве тела ответа об успешном выполнении вместе с длиной содержимого, требуемой протоколом.

Если открыть `localhost:8477` в браузере, должно визуализировать HTML-файл.

Обратите внимание, что если вы также откроете какой-либо маршрут в браузере `localhost:8477/vedant` например, это вернет вам тот же результат. Это не желаемый результат, так как мы хотим управлять ответом на основании того, по какому маршруту сделан запрос `GET`.

Добавление маршрутов

-15

Здесь мы извлекаем строку состояния запроса и проверяем его, чтобы узнать, какой маршрут вызывается клиентом.

Если мы сделаем это, соединение останется открытым для любого маршрута, который не является корнем, и будет не иметь никакого ответа, ни успеха, ни неудачи. Давайте добавим 404 для других маршрутов.

Создание файла 404.html:

-16

Добавить блок `else` в функцию `handle_request`:

-17

Теперь любой маршрут, не являющийся корневым, приведет к ошибкам с содержимым 404.

Рефакторинг кода

Мы можем переделать вышеуказанную функцию, чтобы бы она была более краткой.

-18

Здесь значения `status_line` и имя файла получаются в условии, вроде троичного оператора (но это не точно).

Статья на rusty-code.ru