[Из песочницы] Как REST-архитектура влияет на скорость и надежность работы сайта
В основе REST-архитектуры лежит несколько важных базовых принципов, которые часто упускаются из вида начинающими программистами. Между тем, эти принципы имеют критическое значение для скорости и надежности работы веб-сайта. В некотором смысле REST — это архитектура, концентрирующаяся на совместимости и эффективном взаимодействии с другими узлами сети и клиентским ПО. Для них веб-сайт — черный ящик, реализующий HTTP интерфейс.Унифицированный программный интерфейсКлючевой момент: совместимость с HTTP-методами в плане безопасности и идемпотентности.Безопасный запрос — это запрос, который не меняет состояние приложения.
Идемпотентный запрос — это запрос, эффект которого от многократного выполнения равен эффекту от однократного выполнения.Таблица соответствия HTTP-метода безопасности и идемпотентности:
HTTP-Метод Безопасный Идемпотентый GET Да Да HEAD Да Да OPTIONS Да Да PUT Нет Да DELETE Нет Да POST Нет Нет Что мы видим? GET-запрос не должен менять состояние ресурса, к которому применяется. PUT и DELETE запросы могут менять состояние ресурса, но их можно спокойно повторять, если нет уверенности, что предыдущий запрос выполнился. В принципе, это логично: если многократно повторять запрос удаления или замены определенного ресурса, то результатом будет удаление или замена ресурса. Но POST запрос, как мы видим из таблицы, небезопасный и неидемпотентный. То есть мало того, что он меняет состояние ресурса, так и многократное его повторение будет иметь эффект, зависимый от количества повторений. Ему по смыслу соответствует операция добавления новых элементов в коллекцию: выполнили запрос Х раз, и в коллекцию добавилось Х элементов.Опираясь на понятия безопасности и идемпотентности легче понять, какие именно методы соответствуют операциям в терминах CRUD:
HTTP-метод Операция POST Create GET Read PUT Update DELETE Delete Что из этого следует? При проектировании REST интерфейса надо в первую очередь думать, не о том, как будет выглядеть структура URL, а соответствует ли суть выполняемых операций безопасности и идемпотентности выбранного HTTP метода.Игнорирование принципов безопасности и идемпотентности может привести к разного рода ошибкам и странным эффектам. Если какой-либо обработчик GET-запроса выполняет небезопасную операцию, даже обычный поисковый робот может спровоцировать многократное выполнение этой небезопасной операции.
Отказ хранить состояние клиента и кэширование
Если во время прорисовки страницы мы выводим в боковой колонке имя пользователя, его корзину с товарами, список недавно просмотренных товаров, то эту страницу гораздо сложнее кэшировать таким образом, чтобы кэш был полезен всем посетителям сайта, а не только этому конкретному.
Более того, внутренняя логика усложняется: приходится использовать сессии. При каждой генерации странички приходится инициировать загрузку сессионных данных из хранилища, сохранение сессионных данных в хранилище. Все это выливается в активное чтение и запись на диск или в БД. Часто веб-сайт спроектирован таким образом, что при посещении поисковым роботом, он все равно стартует для него сессию, хотя смысла в этом нет никакого.
REST предлагает нам отказаться или минимизировать хранение состояния клиента на сервере путем переноса данных из сессии в БД и на сторону клиента. Например, список просмотренных товаров мы могли бы хранить в куках, корзину пользователя в БД, а блоки, которые никак не могут обойтись без состояния клиента, подгружать отдельными запросами, чтобы они не мешали кэшировать остальную часть страницы.
Это позволяет закэшировать большинство страниц полностью на продолжительное время, опираясь на возможности HTTP-протокола. В подавляющем большинстве случаев можно обойтись без сложной внутренней логики с кэшированием отдельных SQL-запросов или отдельных блоков страницы через memcache.
REST предлагает нам использовать HTTP-заголовки для управления кэшированием. Это позволяет перенести бремя хранения кэша на клиента, на промежуточные узлы между сервером и клиентом или на специализированное ПО, например, Squid.
Не совсем очевидно, но кэшировать можно не только успешные HTTP-ответы (200 OK), но и другие:
301 (Moved Permanently). Ресурс сменил адрес. Мы можем выставить здесь кэширующий заголовок и пользователь запомнит, куда этот ресурс переехал, и не будет его больше запрашивать 400 (Bad Request). Пользователь прислал неверные данные. Если он в следующий раз пришлет те же данные, результат будет той же самой ошибкой. Можно выставить ему кэширующий заголовок, и запрос повторяться не будет. 404 (Not Found). Ресурс отсутствует. Если он еще долго не появится по этому адресу можно выставить кэширующий заголовок, чтобы предотвратить повторные запросы от этого клиента. 405 (Method Not Allowed). HTTP метод не поддерживается. Можно выставить кэширующий заголовок, если его поддержка в ближайшее время не планируется 410 (Gone). Ситуация такая же, как и с 404. Надеюсь, у меня получилось заинтересовать вас на более глубокое изучение HTTP-протокола и REST-архитектуры. Есть хорошие книги, например, «RESTful Web Services Cookbook». Удачи вам и спасибо за потраченное на статью время!