Пейджинг в коллекции отдыха - PullRequest
126 голосов
/ 29 мая 2009

Я заинтересован в предоставлении прямого интерфейса REST коллекциям документов JSON (представьте себе CouchDB или Persevere ). Проблема, с которой я сталкиваюсь, заключается в том, как обработать операцию GET в корне коллекции, если коллекция большая.

В качестве примера притворяюсь, что я выставляю таблицу Questions StackOverflow, где каждая строка представлена ​​в виде документа (не обязательно, что такая таблица обязательно есть, просто конкретный пример значительной коллекции «документов»). Коллекция будет доступна на /db/questions с обычными CRUD API GET /db/questions/XXX, PUT /db/questions/XXX, POST /db/questions в игре. Стандартный способ получить всю коллекцию - это GET /db/questions, но если при этом наивно выводит каждую строку как объект JSON, вы получите довольно значительную загрузку и много работы со стороны сервера.

Решение, конечно, пейджинговое. Dojo решил эту проблему в своем JsonRestStore с помощью умного расширения, совместимого с RFC2616, с использованием заголовка Range с настраиваемой единицей измерения диапазона items. В результате получается 206 Partial Content, который возвращает только запрошенный диапазон. Преимущество этого подхода перед параметром запроса состоит в том, что он оставляет строку запроса для ... запросов (например, GET /db/questions/?score>200 или что-то подобное, и да, которые будут закодированы %3E).

Этот подход полностью охватывает поведение, которое я хочу. Проблема в том, что RFC 2616 указывает, что на 206 ответе (выделено мое):

Запрос ДОЛЖЕН включать поле заголовка Range ( section 14.35 ) указав желаемый диапазон, и МОЖЕТ включить If-Range поле заголовка ( раздел 14.27 ), чтобы сделать запрос условным.

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

Я подробно рассмотрел RFC в поисках решения, но был недоволен моими решениями и заинтересован в том, чтобы SO взялась за эту проблему.

У меня были идеи:

  • Возврат 200 с заголовком Content-Range! - Я не думаю, что это неправильно, но я бы предпочел, чтобы более очевидный показатель того, что ответом является только частичное содержимое.
  • Return 400 Range Required - Специального кода ответа 400 для требуемых заголовков не существует, поэтому ошибка по умолчанию должна использоваться и считываться вручную. Это также усложняет исследование через веб-браузер (или другой клиент, такой как Resty).
  • Использовать параметр запроса - Стандартный подход, но я надеюсь разрешить запросы в духе Persevere, и это врезается в пространство имен запроса.
  • Просто верните 206! - я думаю, что большинство клиентов не пугались бы, но я бы не стал идти против MUST в RFC
  • Расширьте спецификацию! Return 266 Partial Content - ведет себя точно так же, как 206, но отвечает на запрос, который НЕ ДОЛЖЕН содержать заголовок Range. Я считаю, что 266 достаточно высоко, чтобы не сталкиваться с проблемами столкновения, и это имеет для меня смысл, но я не уверен, считается ли это табу или нет.

Я думаю, что это довольно распространенная проблема, и мне бы хотелось, чтобы это было сделано де-факто, чтобы я или кто-то другой не изобретал велосипед.

Какой лучший способ представить полную коллекцию по HTTP, если коллекция большая?

Ответы [ 12 ]

0 голосов
/ 03 октября 2014

Хотя можно использовать заголовок Range для этой цели, я не думаю, что это было намерением. Кажется, он был разработан для обработки нестабильных соединений, а также для ограничения данных (поэтому клиент может запросить часть запроса, если чего-то не хватает или размер слишком велик для обработки). Вы взламываете нумерацию страниц на что-то, что, вероятно, используется для других целей на уровне коммуникации. «Правильный» способ разбивки на страницы - это типы, которые вы возвращаете. Вместо того, чтобы возвращать объект вопросов, вы должны вместо этого возвращать новый тип.

Так что, если вопросы такие:

<questions> <question index=1></question> <question index=2></question> ... </questions>

Новый тип может выглядеть примерно так:

<questionPage> <startIndex>50</startIndex> <returnedCount>10</returnedCount> <totalCount>1203</totalCount> <questions> <question index=50></question> <question index=51></question> .. </questions> <questionPage>

Конечно, вы контролируете свои типы мультимедиа, поэтому вы можете сделать ваши "страницы" форматом, который соответствует вашим потребностям. Если вы делаете что-то общее, у вас может быть один синтаксический анализатор на клиенте, который будет обрабатывать пейджинг одинаково для всех типов. Я думаю, что это больше соответствует духу спецификации HTTP, а не обманывает параметр Range для чего-то другого.

0 голосов
/ 05 июня 2009

Мне кажется, что лучший способ сделать это - включить диапазон в качестве параметров запроса. например, GET / db / questions /? date> mindate & date . Получив GET для / db / questions / без параметров запроса, верните 303 с Location: / db / questions /? Query-parameters-to-retrieve-the-default-page . Затем укажите другой URL-адрес, по которому тот, кто использует ваш API, получает статистику о коллекции (например, какие параметры запроса использовать, если он / она хочет всю коллекцию);

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...