Какой код состояния перенаправления HTTP является лучшим для этого сценария API REST?

Я работаю над API REST. Ключевые объекты ("существительные") являются "объектами", и каждый объект имеет уникальный идентификатор. Например, получить информацию об объекте с идентификационным нечто:

GET http://api.example.com/v1/item/foo

Новые объекты могут быть созданы, но клиент не добирается для выбора идентификатора. Вместо этого клиент отправляет некоторую информацию, которая представляет тот объект. Таким образом создать новый объект:

POST http://api.example.com/v1/item/
hello=world&hokey=pokey

С той командой сервер проверяет, есть ли у нас уже объект для получения информации hello=world&hokey=pokey. Таким образом, существует два случая здесь.

Случай 1: объект не существует; это создается. Этот случай легок.

201 Created
Location: http://api.example.com/v1/item/bar

Случай 2: объект уже существует. Вот то, где я борюсь... не уверенный, что должен использовать лучший код перенаправления.

301 Moved Permanently? 302 Found? 303 See Other? 307 Temporary Redirect? Location: http://api.example.com/v1/item/foo

Я изучил описания Википедии и RFC 2616, и ни один из них, кажется, не прекрасен. Вот определенные характеристики, которые я ищу в этом случае:

Перенаправление является постоянным, поскольку идентификатор никогда не будет изменяться. Таким образом для эффективности, клиент может и должен выполнить все будущие запросы к идентификационной конечной точке непосредственно. Это предлагает 301, поскольку другие три предназначены, чтобы быть временными.

Перенаправление должно использовать, ДОБИРАЮТСЯ, даже при том, что этим запросом является POST. Это предлагает 303, поскольку все другие, как технически предполагается, снова используют метод POST. На практике браузеры будут использовать, ДОБИРАЮТСЯ для 301 и 302, но это - API REST, не, веб-сайт означал использоваться обычными пользователями в браузерах.

Это должно быть широко применимо и легко играть с. А именно, 303 HTTP/1.1, тогда как 301 и 302 HTTP/1.0. Я не уверен, сколько из проблемы это.

На данном этапе я склоняюсь 303 только, чтобы быть семантически корректным (используйте, ДОБИРАЮТСЯ, не делайте переPOST), и просто высосите его на "временной" части. Но я не уверен, было ли 302 лучше с тех пор на практике, это было то же поведение как 303, но не требуя HTTP/1.1. Но если я спускаюсь по той строке, интересно, еще ли 301 лучше по той же причине плюс "постоянная" часть.

Мысли ценятся!


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

Для URL shorteners, наиболее распространенная операция безусловно получает идентификатором. Например, для http://bit.ly/4Agih5, bit.ly получает идентификатор 4Agih5 и должен перенаправить пользователя к его соответствующему URL.

bit.ly уже имеет API, но это не ДЕЙСТВИТЕЛЬНО УСПОКОИТЕЛЬНО. Ради примера позвольте мне составить БОЛЕЕ УСПОКОИТЕЛЬНЫЙ API. Например, запросы идентификатора могли бы возвратить все виды информации об этом (например, аналитика):

GET http://api.bit.ly/item/4Agih5

Теперь, если я хочу отправить новый URL bit.ly для сокращения, я не знаю идентификатор своего URL заранее, таким образом, я не могу использовать ПОМЕЩЕННЫЙ. Я использовал бы POST вместо этого.

POST http://api.bit.ly/item/
url=http://stackoverflow.com/ (но закодированный)

Если bit.ly не видел этот URL прежде, он создаст новый идентификатор для него и перенаправит меня через 201 Созданный к новому идентификатору. Но если это видело, что URL, все еще перенаправит меня, не внося изменение. Таким образом, я могу поразить то местоположение перенаправления так или иначе для получения информации/метаданных о сокращенном URL.

Как этот пример сокращения URL, в моем приложении, не имеют значения коллизии. Один URL отображается на один идентификатор, и вот именно. Таким образом, действительно не имеет значения, если URL был сокращен прежде или нет; так или иначе имеет смысл указывать на клиент на идентификатор для него, должен ли тот идентификатор быть создан сначала или нет.

Таким образом, я, вероятно, не буду изменять этот подход; я просто спрашиваю о лучшем методе перенаправления для него.Спасибо!

12
задан chollida 15 March 2010 в 16:45
поделиться

3 ответа

Я бы поспорил за 303. Предположим, прямо сейчас hello = world & hokey = pokey однозначно идентифицирует элемент foo, но позже значение hokey элемента foo изменится на «smokey»? Теперь эти исходные значения больше не являются уникальным идентификатором для этого ресурса. Я бы сказал, что временное перенаправление уместно.

11
ответ дан 2 December 2019 в 05:27
поделиться

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

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

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

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

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


На новом примере позвольте предложить совершенно другой подход. Это может не сработать в вашем случае, потому что дьявол всегда кроется в деталях, но, возможно, это будет полезно.

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

Итак, исходя из этого предположения, почему бы просто не использовать

GET /ShortUrl?longUrl=http://www.example.org/en/article/something-that-is-crazy-long.html&suggestion=crazyUrl

Если URL-адрес уже существует, вы можете вернуться.

303 See Other
Location: http://example.org/ShortUrl/3e4tyz

Если раньше не было, вы можете получить

303 See Other
Location: http://example.org/ShortUrl/crazyurl

Я понимаю, что это похоже на то, что мы нарушают правила GET, создавая что-то в ответ на GET, но я считаю, что в этом случае нет ничего плохого, потому что клиент не запрашивал создание сокращенного URL-адреса, и ему все равно. Он идемпотентен, потому что не имеет значения, сколько раз вы его называете.

Один интересный вопрос, на который я не знаю ответа: будут ли прокси кэшировать начальный GET и перенаправлять.Это может быть интересным свойством, поскольку будущие запросы других пользователей для того же URL-адреса могут никогда не попасть на исходный сервер, прокси-сервер может полностью обработать запрос.

10
ответ дан 2 December 2019 в 05:27
поделиться

POST не поддерживает подход «поиск или создание». Сервер не может сказать клиенту: «Я бы создал это, но он уже существует. Найдите здесь существующую запись». Ни один из кодов 2xx не работает, потому что запрос не выполнен. Ни один из кодов 3xx не работает, потому что цель не состоит в том, чтобы перенаправить POST на новый ресурс. И 303 также не подходит, поскольку ничего не изменилось (см. Спецификацию 303).

Что вы могли бы сделать, так это предоставить клиенту форму или шаблон для использования с PUT, который сообщает клиенту, как создать PUT URI. Если PUT приводит к 200, клиент знает, что ресурс существует, и если 201 возвращается, что новый ресурс был создан.

Например:

Шаблон для URI: http: // service / items / {key}

PUT http: // service / items / 456

[data]

201 Created

или

PUT http: // service / items / 456

{ {1}}

[data]

200 Ok

Вы также можете выполнить «создать, но не заменять, если существует», используя If-None-Match:


PUT http://service/items/456
If-None-Match: *

[data]

412 Precondition failed 

Jan

3
ответ дан 2 December 2019 в 05:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: