[НЕТ ЗВУКА] В
предыдущих видео мы рассматривали то, каким образом нам ответить на
http-запрос и обработать какие-то входящие параметры в него.
Однако отправить http-запрос на какой-то внешний другой сервис —
это тоже очень частая операция, и это видео посвящено
как раз тому, каким образом её можно провести.
Рассмотрим следующий код: у нас есть какой-то url,
и мы хотим просто дернуть Get-запрос: дай мне,
пожалуйста, вот, вот это.
Ну всё очень просто.
В Go для этого в пакете http — Net.http — есть функция Get.
Вот.
Куда вы можете передать url и вам вернется респонс.
Респонс — это довольно большая структура,
там есть много всяких данных, хедеры там, статус ответа, тело.
Вот. Тело, конечно, нужно закрывать всегда,
если у вас нет ошибки.
Ну в данном случае я просто дёргаю через Get какой-то url и
дальше просто вывожу вам его на экран.
url сам этот обслуживается на самом деле той же самой программой,
в ней я просто вывожу на экран то, что мне пришло.
Вот.
Но бывает так, что просто Get-запрос, просто url дёрнуть недостаточно иногда.
Мы хотим отправить туда больше данных, например, какие-то хедеры туда
проставить или, например, постзапрос отправить с данными.
Как это сделать?
Ну http.Get — это просто обёртка, хедер для того, чтобы обратиться,
используя дефолтный http-клиент, и сразу создать
просто очень простой http Request и пульнуть его во внешний сервис.
Допустим, если вам нужно создать какой-то уже более крупный метод.
Вы можете создать Request, да, создать структуру данного типа.
Вот в данном случае я указываю метод Get,
указываю какие-то хедеры: вот User-Agent coursera\golang.
Да. После этого дела мне нужно указать там
url, хотя я тоже могу их сразу указать в Request'e.
Но я воспользуюсь функцией url.Parse.
Она мне распарсит url — это, кстати, тоже достаточно частая операция,
если вы хотите из url'а какие-то параметры выдернуть.
Вот. Распаршу url, сразу же его воткну в
Request, и после этого обращусь
к уже внутреннему полю url'a
— Values, и там выставлю ещё какое-то значение.
Вот я выставлю user, и который равен rvasily.
То есть это аналогично тому, что бы я вот тут написал User равно и так далее.
Вот.
Теперь я использую дефолтный клиент, то есть если раньше я вообще полностью...
мне весь реквест оборачивался в хелпер,
то тут я уже использую дефолтный клиент и обращаюсь к его методу Do,
который выполняет мне запрос, уходит на другой сервер.
Я сразу же проверяю ошибку,
делаю в defer закрытие Body — это очень важно, не течём в этих местах!
Вычитываю весь Body и как строчку его также вывожу на экран.
Хорошо.
Вот тут я использовал дефолтный клиент, в предыдущем пункте использовал дефолтный
клиент, на самом деле дефолтный клиент — это плохо.
Почему?
Дело в том, что в дефолтном клиенте нет
никаких таймаутов на время ожидания ответа.
Иногда это может быть очень большой проблемой, когда какой-то внешний сервис,
куда вы ходите, он ушёл на какое-нибудь обслуживание,
или просто его завалили DDOS'ом, или там сломалось что-то.
И ваша программа также висит и ничего не делает.
Вот. Соответственно, хочется иметь таймауты.
Поэтому вы можете не всегда использовать дефолтный клиент.
Точнее, лучше никогда его не используйте.
А для этого есть транспорт.
То есть можно создать структуру транспорта,
у которого есть куча всяких параметров, например, какие-то вы там ходите таймауты,
какие keepalive'ы, сколько у вас коннектов до удалённого сервиса должно быть...
может быть установлено, и когда они будут протухать, через какое время.
Потом вы, используя этот транспорт, создаёте уже клиента,
и у него тоже есть таймаут.
Там очень много опций, их все стоит лучше изучить в документации.
Вот. Хорошо, я тут создал транспорт,
и в этом же примере мы рассмотрим,
каким образом отправить пост-запрос вместе с какими-то данными на удалённый сервис.
Вот, допустим, у меня есть какие-то данные, и я хочу их отправить.
Ну для начала я создаю из них io.Reader.
Используя вот такую вот нехитрую конструкцию,
и вот на такой url я буду их отправлять.
В данном случае я могу тоже не пользоваться прям совсем составлением
запроса с нуля, а воспользоваться тоже хелпером, который уже вернёт мне запрос.
Если Get он сразу отправлял этот запрос, то NewRequest, он мне его просто вернёт.
Итак, я создаю новый Request методом Post указываю url,
указываю Body для него, указываю для него опять-таки Content-Type,
Content-Length — сколько я туда хочу данных передать — и вызываю уже
метод моего клиента, уже не дефолтного клиента, а уже моего.
Вызываю метод Do и куда я передаю Request, который у меня тут создался.
Вот. Всё.
Дальше — как обычно: проверяю ошибку, закрываю Body, и в defer'e,
то есть она, вот эта строчка, выполнится после того,
как функция завершит работу, в конце работы функции.
Вот.
Вычитываю Body и также вывожу его на экран.
Вот. Ну хорошо бы это
теперь продемонстрировать.
Открываем консоль, запускаем сервер, Вот.
Тут вывелось сразу всё.
Я поднял сервер.
Теперь вот мой getHandler, он вывел мне весь входящий Request.
Вот прям все-все его данные.
Вот, например, User-Agent Go-http-client дефолтный, совсем не такой.
Так. А вот запрос, который я отправлял уже сам,
конструируя этот запрос и сам передавая туда данные.
Вот, например, User-Agent, который я передал, coursera/golang.
А вот параметры.
Вот они все здесь есть.
И теперь в конце пост-запрос.
Тут я ввожу просто тело запроса, Вот он есть raw body, id 42, user rvasily.
Вот тот json, который я передал.
То есть теперь я могу, мог бы его там уже распаковать и этот.
Вот таким образом можно делать http-запросы во всякие внешние сервисы.
Это тоже не тяжело, тоже не больно, и всё это есть в стандартной библиотеке,
вам не нужно нигде ничего доставлять.
Хорошо.
Ещё один момент, который стоит рассмотреть.
Тут я поднимал целый сервер для этого,
прям своей программы, чтобы куда-то отправить эти все запросы.
Иногда бывает так, что нам надо покрыть тестами какую-то
функцию, и хорошо бы иметь тестовый функционал для этого.
Об этом мы и поговорим в следующем видео.