Лучшая практика для реализации долгосрочных поисков с помощью REST
Как часть службы REST, мне нужно реализовать поисковый вызов. Основная идея заключается в том, что пользователь может POST новый поиск и получить результаты:
POST http://localhost/api/search
GET http://localhost/api/search?id=123
Однако мой поиск может длиться несколько минут и возвращать частичные результаты до тех пор, пока они не будут выполнены. То есть, запрос GET вернет что-то вроде:
status: running
results: a, b, c.
в то время как следующий GET-запрос может вернуться
status: completed
results: a, b, c, d, e.
Это противоречит семантике запроса RESTful GET. Запрос всегда должен возвращать тот же результат при вызове несколько раз. Например, когда пользователь использует прокси-сервер кэширования, полные результаты могут никогда не доставляться пользователю.
Вопрос: Есть ли способ обеспечить истинную реализацию RESTful для длительных поисковых запросов с частичными результатами?
Ответы
Ответ 1
Во время выполнения поиска вы можете установить соответствующие заголовки ответов (например, Expires
или max-age
), чтобы указать, что ответ не должен быть кэширован (HTTP/1.1 14.9.3, 13.4).
Как только результат поиска будет завершен, вы можете отправить более подходящий заголовок Expires
/max-age
, чтобы разрешить или расширить кешируемость результата.
Бремя будет заключаться в том, что клиент будет повторно запрашивать ресурс до тех пор, пока его статус поиска не будет завершен. Возможно, клиент может использовать значение заголовка Expires, чтобы определить, когда он должен повторно запрашивать обновленные результаты.
Кроме того, вы также можете использовать собственный код состояния 2XX, чтобы указать, что результат еще не завершен. Может быть, HTTP/1.1 299 In Progress
, или что-то имеет смысл. Спецификация указывает, что коды состояния HTTP являются расширяемыми.
Для записи ваше утверждение:
Это противоречит семантике запроса RESTful GET. Запрос всегда должен возвращать тот же результат при вызове несколько раз.
неверно для запросов GET - ресурсы могут меняться. То, что запросы GET являются идемпотентными, означает, что "... побочные эффекты N > 0 одинаковых запросов такие же, как и для одного запроса". [spec]
Ответ 2
Несколько дней назад я случайно наткнулся на сообщение в блоге по reddit, посвященное вашей проблеме. Вы можете проверить это: Bill Higgin RESTy long-ops.
Счастливое чтение.
Ответ 3
Это не проблема, если первый запрос GET возвращает частичные результаты, а второй запрос GET возвращает полные результаты. Это потому, что первый запрос GET не приводит к изменению результата второго запроса: этот запрос вернул бы полные результаты, даже если первый GET не был выпущен. "идемпотент" не означает одинаковых результатов. Это означает, что первое GET не влияет на второе GET.
Было бы проблемой, если первый запрос GET возвратил частичные результаты, а второй GET вернет остальные результаты (сначала GET возвращает A, B, C, а второй GET возвращает D, E, F). Здесь первый GET изменяет второй результат, поэтому он не RESTful.
Ответ 4
Может быть, не самый элегантный ответ, но обойдется в кешировании прокси: просто не отправляйте один и тот же запрос дважды. Добавьте временную метку к запросу (&time=1318355458
). Таким образом, каждый запрос уникален (вы также можете добавить миллисекунды к времени, если вы запрашиваете > 1hz).
Что касается следующей доктрины "Запрос всегда должен возвращать тот же результат при вызове несколько раз", он кажется логически противоречивым цели возвращения частичных результатов в разное время для одного и того же запроса.
Ответ 5
Не могли бы вы подождать вместо опроса, если вы просто хотите получить полные результаты?
Почему вы не можете предоставить ресурс как часть своего POST, который получит результаты PUT? Вы предоставляете интерфейс "обратного вызова" REST, поэтому, вместо опроса, клиентский процесс ожидает PUT для предоставленного ресурса. Затем вы можете либо получить результаты, либо результаты могут быть включены в PUT.