HTTP. Методы запроса
Виды методов http запроса
Рассмотрим методы HTTP запроса. Название метода идет в первой строке в запросе от клиента
GET
Часто используемый и фундаментальный метод, который используется для получения данных с указанного ресурса.
Цель метода - получение информации READ, данные можно только извлекать.
1
GET /index.html
Характеристики
Главные характеристики метода:
Safe(Безопасный), то есть его использование не меняет состояние сервераIdempotent(Идемпотентность), то есть многократный вызов одного и того же запроса будет иметь один и тот же результат- Параметры запроса передаются прямо в адресной строке после символа
?, разделенных символом&, например/223?utm_source=button&utm_medium=referral&utm_campaign=223-FZ&utm_content=newwebsitemenuproduct&utm_term=25Nov - Кеширование. Ответ сервера методом
GETможно кешировать. - Возможность делится ссылками на ресурс. Все что можно загрузить методом
GET, можно скопировать и отправить кому-либо. - Хоть это нигде не прописано, из-за ограничений на длину
url,GETне подходит для передачи больших объемов данных. GETне подходит для передачи приватных данных, так как они передаются в адресной строке.- В качестве ответа на
GETзапрос сервер может вернуть любые данные.
Примеры запроса
1
2
3
4
GET /api/users/123 HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Accept: application/json
Еще немного примеров
1
2
3
4
5
6
7
8
GET https://www.google.com/search?q=что+такое+http&hl=ru&num=10
GET https://shop.example.com/catalog/laptops?brand=apple&sort=price_asc
GET /api/users/123
GET /api/products
GET /api/products?category=electronics&in_stock=true&sort=price_desc
GET /api/articles?page=2&limit=10
GET /api/comments?postId=15&sort=newest&page=1&limit=20
GET /api/users/123?format=json
Для чего подходит
- Загрузка веб страницы
- Получение данных по
apiс фильтрацией - Поискового запроса
- Статический контент
Для чего не подходит
- Операций, которые меняют состояние сервера, создание чего-либо.
- Передачи приветных данных, пароли, личная информация.
- Передача больших объемов данных.
Проектирование api
В качестве примера попробуем спроектировать api. Или как нам бы хотелось, чтобы это выглядело.
Endpoint- это конкретный ресурс к которому на нужен доступ, например/usersQuery params- это параметры которые мы передаем после символа?- Логика обработки - это те правила по которым будет работать наш метод
При проектировании метода нужно понимать, что есть основная сущность.
Например, нужно получить заявки относящиеся к товару, и это будет универсальный вариант
1
2
/requests?product=3456 // Заявки относящиеся к товару
/products?request=67 // Товары относящиеся к заявкам
Тут не рекомендуется выходить за рамки первого уровня иерархии и в URL.
Так же передавать параметры запроса в GET body считается плохой практикой, лучше для этого использовать Query параметры
Не рекомендуется использовать
URLдлиной более 2048 символов.
Так же сложные иерархические данные сложно преобразовать в плоскую строку.
Теперь как быть с сортировкой, здесь можно воспользоваться классическим вариантом
sortполе сортировкиorderпорядок сортировки
1
2
3
4
/requests?product=3456?sort=NAME&order=ASC // По полю NAME по возрастанию
/requests?product=3456?sort=NAME&order=DESC // По полю NAME по убыванию
/requests?product=3456?sortProperty=STATUS&sortDirection=DESC // Меняем поля, но суть от этого не поменяться
/requests?product=3456?sortProperty=PRICE&sortDirection=ASC // Меняем поля, но суть от этого не поменяться
Далее перейдем к фильтрам
1
2
/products?status=0 // Показать все товары со статусом 0
/products?status=NOACTIVE // Показать все товары со статусом NOACTIVE
Это все хорошо, но как сделать множественный фильтр. Можно просто перечислить через ,
1
/products?requests=67,1223,78,56
Теперь перепишем немного примеры добавив множественный выбор
1
2
// Получаем товары указанных заявок отсортированых по полю NAME по возрастанию
/products?sort=NAME&order=ASC&requests=67,1223,78,56
При таком запросе получаем json с результатом.
Здесь нужно учитывать, что некоторые поля могут иметь больше одного свойства.
Лучше все названия писать в едином стиле, например "created_at": "Thu Nov 03 05:19;38 +0000 2011" и не смешивать например "createdAt": 1320296464
По собственным предпочтениям думаю лучше так:
- База данных
created_at apicreatedAt
Ключевые слова:
- Пагинация:
limit,offset,page,pageNumber,pageSize,start,end,count - Поиск:
q,search,text - Диапазон:
startDate,endDate,startAt,range - Сортировка:
sort,sortProperty,order,sortDirection,sort[name]=ASC, sort[email]=DESC
Не обязательно, что-то придумывать можно переиспользовать для разных сущностей, одни и те же свойства.
Главное, что эти названия были согласованы в разных частях системы.
Вернемся к json ответу, тут нужно учивать, что это массив объектов, лучше так же его обернуть в объект.
Например:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
"description": "Описание",
"result": {
"pageNumber": 0,
"pageSize": 67,
"totalCount": 221,
"content": [
{
"id": "12345",
"number": "123",
"status": {
"code": "ACTIVE",
"name": "Активно"
},
"price": {
"avg": "1700",
"min": "1500",
"max": "1900"
}
}
]
}
}
Так же важно учитывать права доступа ко всем действиям, их можно передавать в json.
В идеале под все эти кейсы нужно писать тесты на вашем языке программирования
HEAD
Метод HEAD запрашивает заголовки, ответ на который не должен возвращать тело ответа. По факту HEAD аналогичен GET но без тела ответа.
Основная цель получить READ метаданные о ресурсе, тем самым это делает запрос очень легким.
Характеристики
- Идентичен методу
GETкроме тела запроса, по факту содержит все эти же самые заголовки как иGET. - Нет тела ответа. Сервер не должен ничего возвращать.
- Безопасный метод, так как он не меняет данные на сервере, а просто возвращает заголовки.
- Метод Идемпотентный. При многократном выполнении одного и того же запроса возвращает один и тот же результат
- Запросы могут кешироваться
Для чего подходит
- Может подойти для проверки битых ссылок, чтобы узнать доступна ли страничка, смотря на статус который вернет страница.
- Может помочь понять, размер файла перед его загрузкой, бывает это полезно, при особенно больших файлах.
- Можно проверять не поменялся ли файл на сервере с момента последней загрузки.
- Просто пинг сервера на работоспособность, чтобы не качать содержимое методом
GET.
Идеально подходит, чтобы проверить данные, но не забирать их.
OPTIONS
Метод OPTIONS используется для получения информации READ о возможностях ресурса по указанному url.
Характеристики
- Успешный ответ имеет тело.
- Безопасный, не меняет данные, а только возвращает результат
- Метод Идемпотентный. При многократном выполнении одного и того же запроса возвращает один и тот же результат
1
2
OPTIONS /index.html HTTP/1.1
OPTIONS * HTTP/1.1
Подходит для
- Чтобы определить какие методы разрешены на сервере, обнаружить доступные ресурсы. Это первоначальное предназначение метода
1
2
3
4
5
6
OPTIONS /api/users/123 HTTP/1.1
Host: myapi.com
HTTP/1.1 200 OK
Allow: GET, HEAD, PUT, DELETE, OPTIONS
Content-Length: 0
Это может быть полезно для информирования клиентов о возможностях.
CORSэто еще одна причина, гдеOPTIONSможет помочь.
CORS (Cross-Origin Resource Sharing) - это механизм безопасности в браузерах, который позволяет веб-странице с одного домена (origin) делать запросы к другому домену. Без этого механизма любой сайт мог бы украсть ваши данные с другого сайта, пока вы в него авторизованы.
Браузер не может просто так взять и отправить сложный запрос на другой домен, использовать нестандартные методы, содержать кастомные заголовки.
Чтобы убедиться, что такой “сложный” запрос безопасен, браузер автоматически отправляет предварительный OPTIONS запрос.
Как это может работать из кода
javascriptкод пытается отправитьDELETEзапрос наapiдругого сайта- Браузер видит что это сложный запрос, и отправляет
OPTIONSзапрос со специальными заголовками, чтобы проверить что запрос методомDELETEможно отправлять. - Сервер проверяет политику
CORS - Сервер отвечает на
OPTIONSзапрос - Браузер оригинальный
DELETEзапрос, если все ок, иначе будет ошибкаCORS
1
2
3
4
5
6
7
8
9
10
11
OPTIONS /api/data HTTP/1.1
Host: api.example.com
Origin: https://my-website.com
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: authorization
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://my-website.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: authorization, content-type
Access-Control-Max-Age: 86400
PUT
PUT создает новый ресурс или заменяет (обновляет) его данными из тела запроса PLACE, REPLACE.
1
PUT https://api.example.com/users/123
Характеристики
- Идемпотентность, ключевая характеристика, значит, что один и тот же запрос несколько раз будет выполнен всего один раз. Это делает
PUTзапрос надежным, даже если сетевой завершился ошибкой, его можно повторить, он выполнится только один раз. - Не безопасный, так меняет состояние на сервере, создает или обновляет ресурс.
PUTвсегда в теле содержит полное, новое представление ресурса, нельзя отправить, только часть объекта, нужно отправлять все целиком.- Важно отличать
PUTотPOSTкоторый добавляет данные в коллекцию, аPUTработает с уже созданным ресурсом или создает его. - Еще
POSTбудет с одним и тем же набором данных влечет за собой сторонние, в отличие отPUT
Когда использовать
- Когда нужно полностью заменить состояние ресурса
- Когда операция должна быть идемпотентной, например в финансовой сфере.
- Когда клиент сам определяет
URLнового ресурса
Если целевой ресурс еще не был создан, PUT создает его, в ответе отправит 201 Created, а если сущность была заменена, то в ответе будет 204 No Content.
POST
С помощью метода POST можно отправить данные на сервер, тип тела запроса указывает в заголовке Content-Type.
POST один из основных методов ADD TO COLLECTION.
1
2
3
4
5
6
POST /api/users HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: 54
{"name": "Ivan Petrov", "email": "ivan@example.com"}
Характеристики
- В отличие от
GETвсе данные передается в теле запроса (body). - С помощью
POSTможно создать новую сущность на сервере. POSTне является идемпотентным методом. Это значит, что повторный запуск одного и того же действия будет выполнен столько раз, сколько будет отправки формы например.- Нет ограничения на размер данных, он может ограничиваться только настройками веб-сервера
- Запросы
POSTпо умолчанию не кешируются - Можно сказать что
POSTотносительно безопасен, так как критические данные передаются не в открытом виде, а теле запроса, но это не значит, что их нельзя перехватить. POSTотPUTотличается тем, чтоPOSTпри одном и том же запросе будет выполнять его повторно в отличие отPUT, который выполнит его один раз.
Запрос POST обычно отправляется через html форму и приводит к изменениям на сервере.
Content-Type: application/json Заголовок говорит серверу, в каком формате пришли данные в теле запроса. Какие варианты могут быть:
application/x-www-form-urlencoded- данные из форм по умолчанию.multipart/form-data- используется для отправки файлов.
Если это запрос не из формы у него может быть любой тип
Примеры
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
POST / HTTP/1.1
Host: test.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 13
say=Hi&to=Mom
POST /test.html HTTP/1.1
Host: example.org
Content-Type: multipart/form-data;boundary="boundary"
--boundary
Content-Disposition: form-data; name="field1"
value1
--boundary
Content-Disposition: form-data; name="field2"; filename="example.txt"
value2
--boundary--
Где это может использоваться
- Если нужно отправить личные данные
- При создании новой сущности через
api - Если нужно передать большой объем данных
- Когда не страшно отправить несколько одинаковых запросов на сервер
PATCH
PATCH частично изменяет ресурс. Применяет к ресурсу те изменения которые указаны в теле запроса. То есть некий набор инструкций о том как изменить ресурс.
Характеристики
PATCHПрименяет только указанные изменение, остальные поля остаются без изменений- Идемпотентность не всегда. Результат запроса может зависеть от состояния ресурса
- Тело запроса содержит набор полей для изменения ресурса.
- Если нужно изменить несколько полей
PATCHболее эффективен чемPUT.
Когда можно его использовать
- Обновить одно или несколько полей сущности, или изменить статус сущности.
- Увеличения числа просмотров сущности + экономия трафика, так как меняться только несколько полей сущности.
Пример
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
PATCH /api/users/123 HTTP/1.1
Host: example.com
Content-Type: application/json-patch+json
[
{
"op": "replace",
"path": "/email",
"value": "ivan.petrov.new@example.com"
},
{
"op": "increment",
"path": "/loginCount",
"value": 1
}
]
После запроса изменения применятся только к указанной сущности
Тело запроса
Тело запроса PATCH это на самом деле структурированный документ с набором инструкций.
application/json-patch+json - массив операций который нужно выполнить
Операции которые могут быть: add, remove, replace, move, copy, test.
1
2
3
4
5
6
7
8
9
10
11
12
[
{
"op": "replace",
"path": "/email",
"value": "ivan.petrov.new@example.com"
},
{
"op": "increment",
"path": "/loginCount",
"value": 1
}
]
- еще нестандартная операция
incrementкоторая используется для увеличения счетчика
DELETE
DELETE Удаляет указанный ресурс на сервере
1
DELETE /file.html HTTP/1.1
Характеристики
- Идемпотентность, значит, что запрос будет выполнен только один раз
- Не является безопасным, так как меняет состояние на сервере
Пример
1
2
3
4
DELETE /api/users/123 HTTP/1.1
Host: example.com
Authorization: Bearer <your_access_token>
Content-Type: application/json
Чисто технически можно отправить тело запроса DELETE, но это не рекомендуется, так как не всеми поддерживается.
Что-то важное
- Можно ресурс жестко удалить из базы данных, а можно пометить что он удален, чтобы потом восстановить
- Всегда нужно запрашивать подтверждение удаления записи
- Обязательно нужно с помощью прав доступа закрыть удаление ресурса.
Удалять или не удалять
Подробнее рассмотрим проблему удаления записи из базы данных.
Сперва зададим ряд вопросов.
- Нужно ли восстановить запись. Могут ли случайно удалить запись или данные не имеют ценности после удаления
- Связанные данные. Если ли вероятность потерять связанные данные, если запись будет физически удалена из базы данных. Мягкое удаление с пометкой сохранит целостность истории. Или это не важно, можно удалять смело.
- Юридические аспекты, возможно есть законы которые требуют хранить данные какое-то время даже после их удаления, тогда мягкое удаление тут подходит.
- Насколько важно хранить чувствительные данные пользователя, даже в удаленном состоянии.
- Накопление удаленных данных могут раздувать базу данных, возможно нужно добавить индексы и прочие оптимизации для базы данных
Принятие решения
- Мягкое удаление
- Восстановление данных +
- Целостность данных +
- История +
- Производительность -
- Размер БД -
- Сложность кода -
- Жесткое удаление
- Восстановление данных -
- Целостность данных -
- История -
- Производительность +
- Размер БД +
- Сложность кода +
В базе данных лучше для этого использовать флаг deleted_at с возможностью NULL и временем удаления записи
Обязательно должен быть создан индекс по этому полю
1
CREATE INDEX idx_articles_deleted_at ON articles(deleted_at);
В api лучше усилить проверку на бэкенде
1
2
DELETE /api/articles/123 // Мягкое удаление
DELETE /api/articles/123?force=true // Жесткое удаление с правами и проверками на бекенде
Так же можно поступить используя гибридный подход, например помещать удаленные записи в отдельное хранилище или архивную таблицу, а из рабочей базы данных удалять.
Лучшее планирование гибридного подхода дает лучший результат поддержки проекта в будущем.
CONNECT
Используется для установки туннеля между клиентом и целевым сервером.
1
2
3
CONNECT server.example.com:80 HTTP/1.1
Host: server.example.com:80
Proxy-Authorization: basic aGVsbG86d29ybGQ=
Это больше технический метод запроса
Клиент отправляет запрос прокси серверу
1
2
3
CONNECT google.com:443 HTTP/1.1
Host: google.com:443
Proxy-Authorization: Basic dXNlcjpwYXNzd29yZA==
Далее прокси-сервер проверяет разрешено ли вообще подключаться этому пользователю и разрешены ли CONNECT соединения.
Если соединение разрешено, тогда вернется ответ
1
HTTP/1.1 200 Connection established
Если нет, тогда вернется ошибка например, 403 Forbidden или 407 Proxy Authentication Required.
С этого момента прокси сервер, становиться переадресатом и передает все данные на сервер.
CONNECT не имеет тела запроса. Тело - это весь последующий трафик, передаваемый через туннель.
TRACE
Технический метод предоставляющий механизм отладки используется для диагностических целей
TRACE позволяет клиенту увидеть, какой именно запрос дошел до сервера.
Как это работает
- Клиент отправляет запрос методом
TRACEна сервер. - Запрос проходит через промежуточные узлы, каждый из них может видоизменять заголовки запроса
- Сервер обрабатывает запрос и не выполняет никаких действий с ресурсом. Сервер формирует ответ
200 окс полным содержимым запроса клиента.
1
curl -X TRACE http://example.com/resource -H "My-Custom-Header: Hello" -H "Another-Header: World" -v
1
2
3
4
5
6
7
8
9
HTTP/1.1 200 OK
Content-Type: message/http
TRACE /resource HTTP/1.1
Host: example.com
User-Agent: curl/7.68.0
Accept: */*
My-Custom-Header: Hello
Another-Header: World
Основная задача TRACE - отладка, что помогает ответить на вопросы
- Какие заголовки добавляет мой корпоративный прокси сервер?
- Не изменяет ли файрвол мой запрос?
- Правильно ли мой клиент формирует запрос?
Несмотря на всю полезность
TRACE, сегодня он считается опасным методом и почти всегда отключен на современных браузерах, угроза Cross-Site Tracing (XST)
Рекомендуется всегда выключать метод
TRACEв конфигурации веб-сервера, по умолчанию он выключен
Итог
Если рассматривать CRUD операции, то можно сказать что:
CREATE-POSTREAD-GETUPDATE-PUTDELETE-DELETE
Оптимизация бизнеса, создание сайтов, разработка парсеров или интеграций.
Бесплатно расчитаю время разработки, предложу решение вашей задачи.
