Введение
Representational State Transfer, или сокращенно REST, описывает архитектурный стиль сетевых систем. REST относится к набору архитектурных ограничений и принципов. Приложение или дизайн, который удовлетворяет этим ограничениям и принципам, является RESTful.
концепция:
-
Ресурсы (Resources) REST — это «преобразование состояния уровня представления», фактически он опускает предмет. «Уровень представления» фактически относится к «слою представления» «ресурса». Так что же такое ресурсы? Это изображение, документ, видео и т. д., которые мы обычно посещаем в Интернете. Эти ресурсы расположены по URI, то есть URI представляет ресурс.
-
Представление
Ресурс — это конкретная информация об объекте, которая может быть представлена различными способами. Отображение объекта — это уровень представления, например, текстовое сообщение txt может быть выведено в форматах html, json, xml и других, а изображение может отображаться в jpg, png и т. д., что и является значением уровня представления .
URI идентифицирует ресурс, но как определить его конкретное представление? Он должен быть указан с полями Accept и Content-Type в информации заголовка HTTP-запроса.Эти два поля являются описанием «уровня представления». -
Государственная передача (State Transfer) доступа к веб-сайту представляет собой интерактивный процесс между клиентом и сервером. В этом процессе определенно участвуют данные и изменения состояния. Протокол HTTP не имеет состояния, поэтому эти состояния должны храниться на стороне сервера, поэтому, если клиент хочет уведомить серверную сторону об изменениях данных и состояния, он должен быть уведомлен каким-либо образом.
Спецификация формата URI
- Попробуйте использовать дефис "-" вместо подчеркивания "_" в URI.
- Равномерно используйте строчные буквы в URI
- Не включать расширение файла (скрипта) в URI
прототип ресурса
- Документ
文档是资源的单一表现形式,可以理解为一个对象,或者数据库中的一条记录。在请求文档时,
要么返回文档对应的数据,要么会返回一个指向另外一个资源(文档)的链接。
以下是几个基于文档定义的URI例子:
https://api.example.com/users/will
https://api.example.com/posts/1
https://api.example.com/posts/1/comments/1
- Коллекция
集合可以理解为是资源的一个容器(目录),我们可以向里面添加资源(文档)。例如:
https://api.example.com/users
https://api.example.com/posts
https://api.example.com/posts/1/comments
- Склад (Магазин)
仓库是客户端来管理的一个资源库,客户端可以向仓库中新增资源或者删除资源。
客户端也可以批量获取到某个仓库下的所有资源。仓库中的资源对外的访问不会提供单独URI的,
客户端在创建资源时候的URI除外。例如:
PUT /users/1234/favorites/posts/1
上面的例子我们可以理解为,我们向一个id是1234的用户的仓库(收藏夹)中,
添加了一个id为1的post资源。通俗点儿说:就是用户收藏了一个自己喜爱的id为1的文章。
- Контроллер
控制器资源模型,可以执行一个方法,支持参数输入,结果返回。 是为了除了标准操作:
增删改查(CRUD)以外的一些逻辑操作。控制器(方法)一般定义子URI中末尾,
并且不会有子资源(控制器)。例如:
向用户重发ID为245743的消息
POST /alerts/245743/resend
发布ID为1的文章
POST /posts/1/publish
Преобразование действий в ресурсы
把动作转换成可以执行 CRUD 操作的资源, github 就是用了这种方法。
比如“喜欢”一个 gist,就增加一个 /gists/:id/star 子资源,
然后对其进行操作:“喜欢”使用 PUT /gists/:id/star,
“取消喜欢”使用 DELETE /gists/:id/star
或者使用 POST /gists/:id/unstar
另外一个例子是 Fork,这也是一个动作,但是在 gist 下面增加 forks资源,
就能把动作变成 CRUD 兼容的:POST /gists/:id/forks 可以执行用户 fork 的动作。
Соглашение об именовании URI
- Ресурсы типа Document (Документ) именуются существительными (фразами) единственного числа
- Ресурсы типа коллекции называются существительными во множественном числе (фразами).
- Ресурсы типа Warehouse (Магазин) именуются существительными (фразами) во множественном числе.
- Ресурсы типа Controller (Контроллер) именуются глаголами (фразами)
- Некоторые поля в URI могут быть переменными, которые можно заменить по мере необходимости в реальном использовании.
例如一个资源URI可以这样定义:
https://api.example.com/posts/{postId}/comments/{commentId}
postId,commentId 是变量(数字,字符串都类型都可以)。
- Работа CRUD не должна отражаться в URI. Операторы протокола HTTP сопоставлены с CRUD.
CRUD是创建,读取,更新,删除这四个经典操作的简称
例如删除的操作用REST规范执行的话,应该是这个样子:
DELETE /users/1234
以下是几个错误的示例:
GET /deleteUser?id=1234
GET /deleteUser/1234
DELETE /deleteUser/1234
POST /users/1234/delete
Поле запроса URI
В REST поле запроса обычно используется в качестве дополнения к параметру запроса, а также может помочь идентифицировать уникальный ресурс. Но следует отметить, что,
Поскольку URI предоставляет функции запроса, мы должны обеспечить уникальность результатов независимо от наличия условий запроса.
Возвращаемые данные, соответствующие URI, не должны изменяться (в случае, если ресурс не был изменен).
Кэши в HTTP также могут кэшировать результаты запроса.
- Параметр Query можно использовать в качестве условия фильтра для ресурсов типа Collection или Store, например:
GET /users //返回所有用户列表
GET /users?role=admin //返回权限为admin的用户列表
GET /search/users?q={query}{&page,per_page,sort,order} //根据多条件查询用户
- Параметр Query можно использовать в качестве индикатора разбиения на страницы списка ресурсов коллекции или хранилища.
如果是一个简单的列表操作,可以这样设计:
GET /users?pageSize=25&pageStartIndex=50
如果是一个复杂的列表或查询操作的话,我们可以为资源设计一个Collection,
因为复杂查询可能会涉及比较多的参数,建议使用Post的方式传入,例如这样:
POST /users/search
相关的分页信息还可以存放到 Link 头部,这样客户端可以直接得到诸如下一页、最后一页、上一页
等内容的 url 地址
Status: 200 OK
Link: <https://api.github.com/resource?page=2>; rel="previous",
<https://api.github.com/resource?page=2>; rel="next",
<https://api.github.com/resource?page=5>; rel="last"
X-RateLimit-Limit: 20
X-RateLimit-Remaining: 19
Использование методов HTTP-запроса
- Метод GET используется для получения ресурсов
- Метод PUT можно использовать для добавления/обновления ресурсов типа Store.
- Метод PUT можно использовать для обновления всех свойств ресурса, передавая значения всех свойств при использовании, даже если некоторые значения не изменились
- Метод PATCH обновляет некоторые свойства ресурса. Поскольку PATCH является относительно новым, а спецификация более сложной, существует меньше реальных реализаций.
Обычно вместо этого используйте POST - Метод POST можно использовать для создания ресурса
- Метод POST можно использовать для запуска выполнения ресурса типа контроллера.
- Метод DELETE используется для удаления ресурсов
Использование кодов состояния ответа HTTP
- 200 ("ОК") для общего успеха
- 200 ("ОК") недоступно для возврата ошибки запроса
- 201 ("Создано") ресурс создан
- 202 («Принято») используется для возврата асинхронной обработки ресурса класса управления контроллера, который указывает только на то, что запрос был получен.
Для обработки, которая занимает много времени, обычно используется асинхронная обработка. - 204 («Нет содержимого»). Этот статус может появляться в запросах PUT, POST, DELETE, обычно указывая на то, что ресурс существует,
Однако в теле сообщения не возвращается ни статус, ни информация, связанные с ресурсами. - 301 («Перемещено навсегда») URI ресурса был перемещен, и к нему необходимо получить доступ с использованием нового URI.
- 302 («Найден») устарел, этот код заменен на 303/307 в протоколе HTTP 1.1.
Наше текущее использование 302 отличается от семантики исходного определения HTTP 1.0.Это должно быть только в методе GET/HEAD.
Клиент может выполнять автоматические переходы в соответствии с Location, и наш текущий клиент в основном не оценивает исходный метод запроса.
Выполнять временные перенаправления безоговорочно - 303 ("See Other") возвращает ссылку на URI адреса ресурса, но не заставляет клиента получать статус адреса (посетить адрес)
- 304 («Не изменен») имеет статус, аналогичный 204, ресурс на стороне сервера такой же, как и версия ресурса, к которому последний раз обращался клиент,
Никакая модификация, тело сообщения о ресурсе не возвращается. Его можно использовать для уменьшения нагрузки на сервер. - 307 ("Временное перенаправление") Текущий URI не может предоставить запрошенную услугу Временное перенаправление на другой URI.
В HTTP 1.1 307 используется для замены неправильно используемого 302 в раннем HTTP 1.0. - 400 («Неверный запрос») используется для возврата общей ошибки клиента, а 400 также может использоваться для ошибок, отличных от ошибок 4xx,
Конкретная информация об ошибке может быть помещена в тело - 401 ("Неавторизованный") Ошибка аутентификации при доступе к ресурсу, требующему аутентификации
- 403 («Запрещено») обычно используется для неаутентифицированного доступа к ресурсам, запрещен, например, для некоторых клиентов открывается доступ только к некоторым API,
Хотя другие API могут быть недоступны, вы можете указать статус 403. - 404 ("Не найдено") Ресурс, соответствующий URI, не найден.
- 405 ("Метод не разрешен") Метод HTTP не поддерживается, например, некоторые ресурсы только для чтения, POST/DELETE могут не поддерживаться.
Но заголовок ответа 405 должен объявлять методы, поддерживаемые URI. - 406 ("Неприемлемо") Тип формата данных ресурса, запрошенный клиентом, не поддерживается,
Например, формат данных запроса клиента — application/xml, но сервер поддерживает только application/json. - 409 ("Конфликт") Конфликт состояния ресурса, например, клиент пытается удалить непустой ресурс Store.
- 412 («Precondition Failed») используется, когда условная операция не выполняется.
- 415 ("Unsupported Media Type") Тип данных, поддерживаемый клиентом, не может быть удовлетворен сервером.
- 429 («Слишком много запросов») Клиент отправил слишком много запросов за указанное время, что будет использовано при ограничении текущего
- 500 ("Внутренняя ошибка сервера") Ошибка интерфейса на стороне сервера, эта ошибка не связана с клиентом
HTTP Headers
- Content-Type указывает формат данных тела
- Content-Length body Размер тела данных, по этому индикатору клиент может проверить полноту прочитанных данных.
Вы также можете использовать заголовок, чтобы определить, нужно ли вам загружать тело данных большего размера. - Last-Modified используется для ответов на стороне сервера. Это метка времени последнего изменения ресурса. Клиент (кэш) может использовать его в соответствии с
Эта информация определяет необходимость повторного приобретения ресурса. - Идентификатор версии ресурса на стороне сервера ETag, по этой информации клиент (кеш) может судить о необходимости повторного получения ресурса.
Следует отметить, что если ETag генерируется сервером случайным образом, может возникнуть проблема, связанная с тем, что несколько хостов генерируют разные ETag для одного и того же ресурса. - Ресурсы типа хранилища должны поддерживать условные запросы PUT.
假设有两个客户端client#1/#2都向一个Store资源提交PUT请求,服务端是无法清楚的判断是要
insert还是要update的,所以我们要在header中加入条件标示if-Match,If-Unmodified-Since
来明确是本次调用API的意图。例如:
client#1第一次向服务端发起一个请求 PUT /objects/2113 此时2113资源还不存在,那服务端会
认为本次请求是一个insert操作,完成后,会返回 201 (“Created”)
client#2再一次向服务端发起同一个请求 PUT /objects/2113 时,因2113资源已存在,服务端会
返回 409 (“Conflict”)
为了能让client#2的请求成功,或者说我们要清楚的表明本次操作是一次update操作,我们必须在
header中加入一些条件标示,例如 if-Match。我们需要给出资源的ETag(if-Match:Etag),来表
明我们希望更新资源的版本,如果服务端版本一致,会返回200 (“OK”) 或者 204 (“No Content”)。
如果服务端发现指定的版本与当前资源版本不一致,会返回 412 (“Precondition Failed”)
- Расположение используется в заголовке ответа, который обычно является URI ресурса, интересующим клиента. Например, после успешного создания ресурса мы
Вы можете поместить новый URI ресурса в местоположение. Если это запрос на создание ресурса асинхронно, интерфейс ответит 202 («Принято»)
В то же время он может дать клиенту адрес для асинхронного запроса статуса - Cache-Control, Expires, Date улучшают производительность интерфейса через механизм кэширования, а также могут быть отключены в соответствии с реальными потребностями.
Клиент кэширует запросы интерфейса. Для интерфейсов REST, если требования к реальному времени некоторых интерфейсов не высоки, мы можем сделать
Используйте max-age, чтобы указать небольшое время кэширования, что выгодно как для клиента, так и для сервера. Обычно только для GET
метод и вернуть 200, используйте кеш.В некоторых случаях мы также можем кэшировать возврат 3xx или 4xx.
Чтобы предотвратить нагрузку, вызванную неправильным доступом. - Мы можем настроить некоторую информацию заголовка для связи между клиентом и сервером, но не можем изменить характер метода HTTP. поскольку
Заголовок определения должен быть максимально простым и понятным, и не дополнять его информацией в теле.
Адрес и версия API
Рекомендуется указывать версию API в URL-адресе. Если API сильно изменится, вы можете оформить API как имя поддомена.
Напримерapi.github.com/v3; также можно просто поставить версию... пример.com/API/V1.
В качестве альтернативы укажите номер версии в заголовке HTTP.
лимит скорости
Если количество доступов не контролируется, очень вероятно, что API будет злоупотреблять или даже атакован DDos. Ограничение потока пользователей в соответствии с их разными идентификаторами может предотвратить такие ситуации и снизить нагрузку на сервер.
После ограничения потока запросов пользователя должен быть способ сообщить пользователю об использовании его запроса, три связанных заголовка, используемые Github API:
- X-RateLimit-Limit: максимальное количество запросов, которые пользователь может отправлять в час.
- X-RateLimit-Remaining: количество доступных запросов, оставшихся в текущем временном окне.
- X-RateLimit-Rest: при сбросе временного окна количество запросов, доступных в этот момент времени, станет значением X-RateLimit-Limit.
Для запросов, которые превышают трафик, код состояния 429 Слишком много запросов может быть возвращен с сообщением об ошибке.