Как стать автором
Обновить

Комментарии 31

Срасибо. Вы предлагаете собирать веб страницу на стороне клиента или все же на стороне сервера?
Страницу можно собрать на сервере, не включая туда данные, зависящие от состояния текущего клиента. Если необходимо отрисовать элементы, зависящие от состояния клиента, то клиент или берет их из своего хранилища, или запрашивает на сервере.
Отлично. И вместо одного GET запроса будет 100500 запросов к апи по любому чиху. За такое проектирование я бы палкой по рукам бил.
Отказ от сессий невозможен. Так или иначе, но сессии будут «изобретены»
Заместо одного GET-запроса — два. Причем один из них с большой вероятностью берется из кэша, а второй в идеальном случае может не выполняться, если нет необходимости забирать с сервера пользовательские данные. От сессий отказываться не обязательно.
Нет, не два.
Навскидку:

1) userinfo
2) комментарии к товарам/записям
3) отображение самих товаров в зависимости от настроек приватности
4) непрочтенные сообщения
5) еще какая-нить хня — чатик там
и т.п.

Так что нет.
Если есть необходимость оптимизировать по количеству запросов, то для пользовательских данных гипотетически можно использовать один композитный ресурс и забрать их одним GET-запросом.
Тут прекрасная абстракция REST и потекла…
Насколько я понимаю, тут всё сильно завязано на AJAX. Окончательная «сборка страницы» происходит в браузере.
REST-архитектура решает задачи сохранения данных, но практически всегда стоит вопрос об изменении данных на сервере и получения обновлений на клиенте. Именно поэтому в REST часто пролазят всякие адреса описывающие действие, а не состояние и костыли в виде перезапросов изменения состояния по таймауту. Но по сути это отдельные сущности в рамках одной системы:
— хранение данных (REST)
— уведомление об изменениях (Pull/Push)
— модификация данных (серверная или клиентская логика)
Отсутствие формального описания всей системы в целом создает неправильное представление о REST, как о неполной архитектуре.
Но это не значит что REST сломана! REST это не silver bullet.

REST чаще всего описывается поверх HTTP, расширив модель можно добавить RestEvents поверх Server-Sent Events, WebSocket и т.д.
А в расширение RestActions можно добавить блокировки, транзакционность и прочее.
Нельзя сводить все к REST, там, где мы оперируем цельными ресурсами и файлами, там можно использовать Stateless подход, а где явно есть множество глаголов, то нужен RPC. Основное преимущество REST — ответ на вопрос «зачем?» это масштабирование. Потому, что RPC обычно имеет состояние, более того, состояние прямо в памяти сервера, да еще и долговременное соединение (вебсокеты, SSE, long polling). Но это не значит, что RPC не может масштабироваться, ему просто нужен другой балансировщие, не раундробин, а приклеивание по IP или по Cookie, а если RPC происходит через двунаправленный и долгосрочно открытый вебсокет, то и прилипание не нужно, потому, что сам вебсокет и есть состояние, к сокету состояние на сервере или сессия и приклеивается, и сервер не меняется пока не разорвется связь.

Вполне хороший подход, когда вся статика работает через REST, это же файлы их так и обрабатывает с отдельного домена, а вся динамика работает через RPC и вебсокеты (с другого домена), а урлы идентифицируют не ресурсы, а методы (глаголы). Более того, когда на клиенте развивается направление байндинга данных и GUI (тот же React), то байндить же можно и дальше сквозь сокет прямо на сервер и это прекрасно. При чем, синхронизацию состояний можно оптимизировать, чтобы не передавать все изменения мгновенно, а накапливать буфер или за малый временной промежуток и пересылать пачкой. В базу или на диск сервер может читать/писать исключительно в отложенном режиме, состояние нужно конечно персистать, но это же не нужно делать прямо во время запроса, можно отдать ответ и уже неспешно сохранить, да еще и склеить изменения за определенное время.

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

Тут подробнее http://habrahabr.ru/post/204958/
Целью статьи не было все свести к REST, здесь изложена классификация HTTP-методов в плане безопасности и идемпотентности, а так же сделан акцент на совместимости и компоновке веб-приложения, которая облегчила бы прозрачное кэширование значительной части контента на клиенте и промежуточными узлами. Понятно, что окружающий мир многообразен, и редко какая методология, архитектура или модель охватывает все его нюансы.

REST вполне неплохо работает и с композитными ресурсами, и с вычислениями, и с асинхронными задачами. Выкручивать руки себе не надо, согласен, надо брать лучшее и осмысленно это использовать.
Не могу выразить, насколько этого понимания не хватает широкой общественности.
Как-то я не понял, почему вы напрямую связали RPC и stateful. Не вижу проблемы сделать RPC stateless, потому как в самом RPC-подходе нет упоминания о том, как должно храниться или не храниться состояние. Более того, если использовать RPC в концепции «чистой функции», тогда подход становится поистине stateless и вся масштабируемость REST-подхода никуда не пропадает.

Единственное что действительно концептуально отличает RPC от REST — это стандартизация и унификация интерфейсов. Ну и то, что в основе RPC лежат «действия», а в REST — «ресурсы».
Да ладно, 301 разве хуже?
В реальных проектах с пользователем, который прошел аутентификацию, без сохранения состояния на сервере не обойтись. Иногда умиляют молодые программисты, которые гордо отказываются от сессии и вводят, например, токен. Хотя известно, что все это приводит в конечном результате к одному и тому же — передаче сгенерированного случайного числа в куках. И неважно что оно означает. Сессию, токен, или еще что-нибудь. И сервер по прежнему по этому числу будет восстанавливать состояние, предварительно сохраненное.
Надо разделять понятия: хранить состояние клиента (как субъекта отношений клиент-север) и хранить пользовательские данные. Например, флаг «держать меню свернутым» — это скорее состояние клиента, о нем вообще сервер не должен ничего знать, а тем более хранить у себя. Но список заказов конкретного пользователя — это пользовательские данные. И их, конечно, надо показывать авторизованному пользователю, если он их хозяин. Факт авторизации, конечно, можно хранить в сессии. Но если прорисовываем нейтральную по отношению к пользователю информацию (например, страницу товара), почему основной контент страницы не сделать свободным от состояния клиента и, возможно, от сессий вообще, особенно, если большинство пользователей этой страницы — не авторизованные.
Например, флаг «держать меню свернутым» — это скорее состояние клиента, о нем вообще сервер не должен ничего знать, а тем более хранить у себя.

Пользователь может мигрировать между клиентами, нынче это обычное дело.
Семантика конкретных данных в приложении зависит от этого самого конкретного приложения. Если пользователь мигрировал на другой клиент и есть необходимость вместе с миграцией перенести данные, то эти данные — пользовательские и их надо хранить на сервере.

Смысл в том, чтобы не хранить на сервере состояние клиента, как субъекта отношений клиент-сервер.

Данные конкретного пользователя, который подключается через разные клиенты, хранить надо. Но что считать пользовательскими данными, а что считать состоянием клиента, решает разработчик приложения.
Я вообщем-то к этому и веду. Если взять любой реальный проект, чуть сложнее сайта-визитки, то в нем, с вероятностью 100%, потребуется хранить состояние на сервере. А это означает нарушение принципов REST. Тогда возникает вопрос — зачем усложнять приложение и вводить клиентский кэш?

Для себя я выбрал следующую формулу. Кэш на клиенте используется в редких случаях. В основном, в страницах, требующих повышенной производительности. По умолчанию, данные пользователя хранятся в сессии.
Хранение пользовательских данных на сервере не нарушает принципов REST. Нарушает принципы REST хранение состояния клиента. Надо смотреть конкретные примеры, конкретные приложения, конкретные данные, чтобы разговор был предметный.

Ввести клиентский кэш — не самоцель. Во многих случаях публичный клиентский кэш вообще нельзя использовать по соображениям безопасности.
Всё хочу спросить у аппологетов REST-а: как соотносятся PUT и DELETE запросы (небезопасные но идемпотентные) с состоянием гонки?

Что должно быть, если два клиента, например, будут выполнять PUT к одному ресурсу по очереди:

1: PUT
2: PUT
1: PUT < — должен ли этот PUT изменять ресурс?
Правильная практика примерно следующая: PUT возвращает в заголовках ревизию ресурса, повторная перезапись производится, только если передана правильная актуальная ревизия.

P.S. Апологет.
Все PUT запросы могут быть отправлены до получения какого-либо ответа.
Тогда 2 и 3 просто отлупятся с 409
Для этого предусмотрены HTTP-заголовки: If-Match и If-Unmodified-Since.
1: PUT (известна дата изменения — именуем D1, возвращает ETag — именуем E1)
2: PUT (может, конечно, отправить запрос без предварительных условий, но это не правильно)
1: PUT (задаем два условия: If-Match: E1, If-Unmodified-Since: D1)
PUT предполагает, что ресурс по заданному урлу (пере)задаётся полностью. Обновлять записи через PUT неудобно — нельзя обновить запись частично. Для частичного изменения ресурса предназначен метод PATCH:

tools.ietf.org/html/rfc5789

Правильное соответствие REST — CRUD выглядит примерно так:

Create — PUT
Read — GET
Update — PATCH дпя частичного обновления, PUT для перезаписи
Delete — DELETE

А что же POST? Теоретически, POST-ом можно создавать ресурсы, но это не совсем REST-way.
POST изменяет состояние ресурса таким образом, что это не может быть отражено прямым URL
Например, если пользователь имеет право выбирать id своей записи, то он делает PUT /records/{id} — кладёт новый ресурс, доступный по URL. Операции PUT и GET в этом смысле симметричны — что положено по урлу PUT-ом, то можно получить по этому же урлу GET-ом.
Но вот если id генерируется сервером, и пользователь его наперёд знать не может — тогда делается POST /records и в ответе возвращается id.
Другое очевидное применение POST — это всевозможные служебные запросы не имеющие прямых урлов. Ну, например, если нужно заапдейтить много записей сразу, делается ручка /updater, на которую POST-ом передаются параметры операции.
«Как REST-архитектура влияет на скорость и надежность работы сайта» — так же, как наличие домашней собаки влияет на долголетие ее хозяина. То есть, напрямую собака на это никак не влияет, но ее приходится регулярно выгуливать, укрепляя таким образом свое здоровье.
Исходя из главного принципа REST — stateless — очевидно, что сервер, таким образом, будет разгружен, но станет ли от этого быстрее сайт в целом — еще вопрос.
инициировать загрузку сессионных данных из хранилища, сохранение сессионных данных в хранилище. Все это выливается в активное чтение и запись на диск или в БД


Почему вы не рассматриваете вариант сохранения данных сессии в памяти?
Можно сессию и в памяти хранить, если обеспечить, чтобы данные не удалялись при недостатке памяти. Но сам факт переноса сессии с диска или БД, например, в память, говорит о том, что с хранением её на диске или БД возникли сложности. Таким образом можно любые часто используемые данные, с которыми у нас проблемы, перенести в память.

В самой сессии ничего плохого нет. Плохо, когда в ней хранят совсем не подходящие для неё данные. Я видел реализации, когда помещали в сессию десятки мегабайт данных на каждого пользователя и обновляли их при каждом запросе, что вызывало при значительном количестве пользователей проблемы.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации