Документация Vibe.d на русском языке. HTTP

Перевод документации к Vibe.d. Часть 2.

Конфигурация сервера

HTTP-сервер поддерживает некоторое количество параметров конфигурации для настройки его поведения. По умолчанию сервер будет прослушивать все локальные сетевые адаптеры на порту 80 и выполнять полный синтаксический анализ запроса. Далее предоставлен обзор наиболее распространенных настроек:

port

Порт, на котором должен прослушиваться HTTP-сервер.

bindAddresses

Список всех интерфейсов, на которых должен прослушиваться сервер. Поддерживаются адреса IPv4 и IPv6, а также имена доменов.

options

Управляет дополнительными функциями веб-сервера. Некоторые параметры могут быть отключены для увеличения скорости или уменьшения использования памяти. По умолчанию включены следующие параметры: parseURL, parseQueryString, parseFormBody, parseJsonBody, parseMultiPartBody, parseCookies.

errorPageHandler

Предоставляет способ настройки страниц ошибок.

Например:

void errorPage(HTTPServerRequest req,
	HTTPServerResponse res,
	HTTPServerErrorInfo error)
{
	res.render!("error.dt", req, error);
}
 
shared static this()
{
	auto settings = new HTTPServerSettings;
	settings.errorPageHandler = toDelegate(&errorPage);
	// ...
}

Переменные req, code и msg доступны внутри шаблона error.dt.

tlsContext

Позволяет серверу работать как сервер с HTTPS. Скорее всего, вам также придется указать порт 443, если это поле выстановлено.

HTTPS

Для обслуживания HTTPS-соединений конфигурация должна иметь TLS-окружение, имеющее соответствующий сертификат и файлы секретных ключей:

auto settings = new HTTPServerSettings;
settings.port = 443;
settings.bindAddresses = ["127.0.0.1"];
settings.tlsContext = createTLSContext(TLSContextKind.server);
settings.tlsContext.useCertificateChainFile("server-cert.pem");
settings.tlsContext.usePrivateKeyFile("server-key.pem");

Выбор поставщика TLS

В настоящее время поддерживаются два провайдера TLS: OpenSSL и порт Botan для D. По умолчанию для обеспечения функциональности TLS/HTTPS используется OpenSSL. Чтобы выбрать другого поставщика или избежать компиляции с поддержкой TLS, необходимо выбрать соответствующую конфигурацию сборки для подпакета vibe-d: tls:

dependency "vibe-d:tls" version="*"
// use "notls" instead of "botan" to disable TLS support
subConfiguration "vibe-d:tls" "botan"

При использовании рецепта на основе JSON, два параметра должны быть выставлены следующим образом («…» являются просто заполнителями для других возможных директив):

{
	…
	"dependencies": {
		…
		"vibe-d:tls": "*"
	},
	"subConfigurations": {
		…
		"vibe-d:tls": "botan"
	}
}

Маршрутизация

Класс URLRouter предоставляет удобный способ позволить различным функциям обрабатывать разные URL-адреса.  Он поддерживает статическое сопоставление пути, переменные заполнители и wild-cards (неизвестные заранее URL).  Любая совпадающая переменная будет доступна как элемент словаря params.

В дополнение к пути, HTTP-метод также используется для сопоставления запросов.  Каждый метод HTTP-запроса имеет соответствующий метод в классе URLRouter (например, get или post). Следующий пример направит все GET-запросы, соответствующие схеме пути «/users/*», в обработчик userInfo и будет обслуживать все другие GET-запросы с использованием файлов в папке serveStaticFiles, см. serveStaticFiles.

Пример: маршрутизация GET / POST и статического файла:

import vibe.d;
 
void userInfo(HTTPServerRequest req, HTTPServerResponse res)
{
	auto username = req.params["user"];
	render!("userinfo.dt", username)(res);
}
 
void addUser(HTTPServerRequest req, HTTPServerResponse res)
{
	enforceHTTP("user" in req.form, HTTPStatus.badRequest, "Missing user field.");
	res.redirect("/users/"~req.form["user"]);
}
 
shared static this()
{
	auto router = new URLRouter;
	router.get("/users/:user", &userInfo);
	router.post("/adduser", &addUser);
	router.get("*", serveStaticFiles("./public/"));

	// Чтобы уменьшить избыточность кода, можно
	// использовать цепочку методов:
	router
		.get("/users/:user", &userInfo)
		.post("/adduser", &addUser)
		.get("*", serveStaticFiles("./public/"));

	listenHTTP(new HTTPServerSettings, router);
}

Шаблоны Diet

Vibe.d поддерживает HTML-шаблоны с синтаксисом, по большей части совместимым с шаблонами Pug. Они обеспечивают краткий способ динамической генерации HTML-кода конечных веб-страниц. Выражения D и константы могут быть встроены в них, а полный vibe.d API доступен в шаблонах.

Шаблоны должны находиться где-то внутри папки «views» проекта. Затем они отображаются с помощью функции render, которая принимает имя файла шаблона в качестве первого аргумента шаблона, а затем список переменных, которые должны быть доступны шаблону. Наконец, для визуализации требуется HTTPServerResponse.

В следующем примере показан ряд функций компилятора шаблона Diet. Полную ссылку на синтаксис шаблона можно найти на странице шаблонизатора Diet.

Пример файла шаблона с динамическими вставками кода и несколькими другими функциями шаблона:

doctype html
html
	head
		title Страница: #{pageTitle}
	body
		h1= pageTitle
		p Это контент данной страницы.
			| Заголовок "#{pageTitle}" вставлен динамически.
			| Вы можете использовать циклы и другие выражения D:
		block placeholder
		p
			- foreach(i, ch; pageTitle)
				| #{i+1}. символ: #{ch}
		p.special.small Этот параграф имеет 'special'
			| и 'small' CSS классы
		p#footer Этот параграф имеет id 'footer'.
		#somediv.
			А это многострочный текст
			внутри блока div #somediv

Страницы ошибок

Существует три способа возврата страницы ошибки клиенту:

  • Исключение произошло в обработчике запроса или при разборе запроса. По умолчанию возвращается 500 «Внутренняя ошибка сервера». HTTPStatusException, код состояния можно настроить.
  • Обработчик запроса не пишет ответ. В этом случае сервер автоматически возвращает ошибку 404 «Not Found».
  • Обработчик запроса вручную устанавливает статус ошибки в statusCode и записывает тело. В этом случае страница с ошибкой будет точно такой, как указано в коде.

HTTPServerSettings можно использовать для предоставления настраиваемого обработчика страницы ошибок. Если он предоставлен, то вызывается для любого из первых двух условий и должен отображать страницу с ошибкой для объекта ответа. Если обработчик не указан, создается простая страница с ошибками в виде простого текста. См. пример конфигурации HTTP-сервера.

Аутентификация

В настоящее время реализованы методы аутентификации HTTP-Basic-Auth и HTTP-Digest-Auth. Механизмы более высокого уровня, такие как OAuth, будут предоставляться с использованием библиотек расширений.

Простым способом подключить аутентификацию в веб-приложении является использование сквозной функции URLRouter. Если пользователь правильно аутентифицирован, функция performBasicAuth ничего не сделает, и URLRouter будет по-прежнему соответствовать запросу ко всем следующим маршрутам.  Однако если нет аутентификации или если пара имя пользователя / пароль недействительна, будет генерироваться исключение HTTPStatusException, которое сгенерирует на стороне браузера страницу ошибки 403 с диалоговым окном для ввода пароля пользователем. В таком случае маршрутизация останавливается до тех пор, пока пользователь не введет верные данные.

Обратите внимание, что при разработке веб-приложений перед началом работы рекомендуется использовать веб-фреймворк высокого уровня. См. пример веб-проекта реализации сессии, основанной на аутентификации с такой настройкой.

Пример использования HTTP-Basic-Auth для ограничения доступа:

import vibe.d;
 
bool checkPassword(string user, string password)
{
	return user == "admin" && password == "secret";
}
 
shared static this()
{
	auto router = new URLRouter;
	// доступны следующие два маршрута без аутентификации:
	router.get("/", staticTemplate!"index.dt");
	router.get("/about", staticTemplate!"about.dt");

	// далее любой запрос сопоставляется и проверяется для аутентификации:
	router.any("*", performBasicAuth("Site Realm", toDelegate(&checkPassword)));

	// следующие маршруты могут быть достигнуты только после аутентификации:
	router.get("/profile", staticTemplate!"profile.dt");
	router.get("/internal", staticTemplate!"internal.dt");

	// ...
}

Сесии (сеансы)

HTTP-сессии на основе файлов cookie поддерживаются непосредственно HTTP-сервером. Чтобы иметь возможность использовать их, сначала необходимо установить SessionStore в настройках HTTPServerSettings. Затем сеансы устанавливаются путем вызова HTTPServerResponse.startSession и удаляются HTTPServerResponse.terminateSession. Возвращаемый объект Session ведет себя как хранилище «ключ-значение», используя строки в качестве ключей и значений.

Пример использования HTTP-сессии для аутентификации пользователей:

import vibe.d;

void login(HTTPServerRequest req, HTTPServerResponse res)
{
	enforceHTTP("username" in req.form && "password" in req.form,
		HTTPStatus.badRequest, "Missing username/password field.");

	// todo: проверить user/password здесь

	auto session = res.startSession();
	session.set("username", req.form["username"]);
	session.set("password", req.form["password"]);
	res.redirect("/home");
}

void logout(HTTPServerRequest req, HTTPServerResponse res)
{
	if (res.session) res.terminateSession();
	res.redirect("/");
}

void checkLogin(HTTPServerRequest req, HTTPServerResponse res)
{
	// принудительно перенаправлять на / не аутентифицированных пользователей
	if (!req.session)
		res.redirect("/");
}
 
shared static this()
{
	auto router = new URLRouter;
	router.get("/", staticTemplate!"index.dt");
	router.post("/login", &login);
	router.post("/logout", &logout);
	// ограничиваем все следующие маршруты для аутентифицированных пользователей:
	router.any("*", &checkLogin);
	router.get("/home", staticTemplate!"home.dt");

	auto settings = new HTTPServerSettings;
	settings.sessionStore = new MemorySessionStore;
	// ...
}

Запросы клиентов

Клиентский запрос выполняется с использованием функции requestHTTP. Пример выполнения простого HTTP-запроса:

import vibe.vibe;

void main()
{
	requestHTTP("http://google.com",
		(scope HTTPClientRequest req) {
			// можно добавить здесь заголовки перед отправкой,
			// пишите тело POST или делайте что-то подобное здесь
		},
		(scope HTTPClientResponse res) {
			logInfo("Ответ: %s", res.bodyReader.readAllUTF8());
		}
	);
}

Обратите внимание, что вы можете не указывать явные типы параметров HTTPClientRequest и HTTPClientResponse. Они будут автоматически выведены компилятором.

Пул соединений используется внутри совместно с постоянными HTTP-соединениями (keep-alive) для получения максимальной пропускной способности.

Bagomot

Эколог, почти программист-самоучка, мучаю майнкрафт bagomot@zel.crux

Добавить комментарий