HTTP-статус 412 (предварительное условие не выполнено) и управление версиями базы данных - PullRequest
11 голосов
/ 01 сентября 2010

Я реализую веб-сервис RESTful, который обращается к базе данных. Объекты в базе данных имеют версии для обнаружения нескольких обновлений. Например, если текущее значение равно {"name":"Bill", "comment":"tinker", "version":3}, если одно пользовательское PUT {"name":"Bill", "comment":"tailor", "version":3}, запрос будет выполнен успешно (200 OK) и новое значение будет {"name":"Bill", "comment":"tailor", "version":4}. Если второй пользователь помещает {"name":"Bill", "comment":"sailor", "version":3"}, этот запрос не будет выполнен (конфликт 409), поскольку номер версии не совпадает.

Существуют интерфейсы без RESTful, поэтому дизайн баз данных нельзя изменить. Интерфейс RESTful вызывает существующий интерфейс, который обрабатывает детали проверки версии.

Основное правило в веб-сервисах RESTful - всегда следовать подробностям HTTP. Было бы лучше в этом случае использовать условный заголовок в запросе и возвращать 412 Precondition Failed, если версия не совпадает? Соответствующий заголовок выглядит как If-Match. Этот заголовок принимает ETag (Entity Tag), который может быть хэшем представления текущего состояния ресурса.

Если бы я сделал это, ETag был бы для удобства, потому что версия все еще была бы реальной, для которой я тестирую.

Есть ли какая-то причина, по которой я должен это делать, кроме как "сделать его более ОТЛИЧНЫМ", что бы это ни значило?

1 Ответ

19 голосов
/ 02 сентября 2010

Нужно всегда следовать спецификации HTTP, если вы используете HTTP, и причина в том, чтобы просто позволить людям, которые разбираются в спецификации, правильно функционировать .

412 следует использовать только в том случае, если предварительное условие (например, If-Match) вызвало сбой при сопоставлении версии, тогда как 409 следует использовать, если объект вызовет конфликт ( Сама спецификация HTTP ссылается на это поведение в определении 409 ).

Следовательно, клиент, который не отправляет ETag, не будет ожидать 412. И наоборот, клиент, который отправляет ETag, не поймет, что это ETag вызывает 409.

Я бы придерживался одного пути. Вы говорите, что «схема базы данных не может измениться», но это не мешает вам (прямо на уровне HTTP-сервера) извлечь версию из представления базы данных и поместить ее в ETag, а затем на пути, возьмите заголовок If-Match и поместите его обратно в поле версии.

Но делать это полностью в самом теле сущности не запрещено. Вам просто нужно объяснить концепцию и то, как она работает, тогда как с помощью решения ETag вы можете просто указать людям на спецификацию HTTP.

Редактировать: И флаг версии не обязательно должен быть хешем текущего ресурса; версия вполне приемлема. ETag: "3" - это совершенно правильный ETag.

...