Golang: Работы с HTTP запросами часть 2
В предыдущей статье мы рассмотрели как отправлять GET запросы и работать с данными в JSON формате. Но что делать, если мы хотим передавать значения формы? Давайте рассмотрим остальные возможности Go для работы с HTTP запросами.
Для отправки данных в виде формы у нас есть удобная функция http.PostForm. Эта функция принимает два параметра url и url.Values из пакета net/url.
url.Values - это настраиваемый тип, который на самом деле представляет из себя map[string][]string структуру. То есть - это объект, который содержит ключи в виде строк и каждый ключ может содержать несколько строковых значений ([]string). В запросе формы вы можете отправить несколько значений по одному имени поля. Вот почему это фрагмент строки, а не только ключ к значению сопоставления.
Вот пример фрагмента кода:
func MakeRequest() { formData := url.Values{ "name": {"masnun"}, } resp, err := http.PostForm("https://httpbin.org/post", formData) if err != nil { log.Fatalln(err) } var result map[string]interface{} json.NewDecoder(resp.Body).Decode(&result) log.Println(result["form"]) }
Чтобы получить наши значения, мы должны для начала считать его из переменой result и обратиться к нему по ключу.
Кастомный Clients/Requests
Функции http.Get, http.Post или http.PostForm используют заранее созданный для нас стандартный клиент. Но теперь мы увидим, как мы можем инициализировать наш собственный экземпляр Client и использовать его, чтобы сделать новый объект Request. Давайте сначала посмотрим, как мы можем создавать экземпляр объекта Client и выполнять же запросы, которые мы делали ранее.
Ниже приведен краткий пример:
func MakeRequest() { client := http.Client{} request, err := http.NewRequest("GET", "https://httpbin.org/get", nil) if err != nil { log.Fatalln(err) } resp, err := client.Do(request) if err != nil { log.Fatalln(err) } var result map[string]interface{} json.NewDecoder(resp.Body).Decode(&result) log.Println(result) }
Как вы можете видеть, мы просто берем новый экземпляр http.Client, а затем создаем новый запрос, вызывая функцию http.NewRequest. Он принимает метод запроса, url и тело запроса. В нашем случае это простой GET запрос, поэтому третьим параметром мы передаем значение nil. Затем мы вызываем метод Do у нашего модуля Client и анализируем тело ответа. Вот и все: создайте клиент, создайте запрос, а затем позвольте клиенту выполнить запрос. Интересно, что у клиента также есть удобные методы, такие как Get, Post, PostForm - поэтому мы можем напрямую их использовать. Это то, что на самом деле делают http.Get, http.Post, http.PostForm и другие функции модуля http. Они вызывают эти методы в DefaultClient, который уже создан заранее. Фактически, мы могли просто сделать:
func MakeRequest() { client := http.Client{} resp, err := client.Get("https://httpbin.org/get") if err != nil { log.Fatalln(err) } var result map[string]interface{} json.NewDecoder(resp.Body).Decode(&result) log.Println(result) }
И это сработает аналогично предыдущему примеру. Теперь вы можете спросить: почему бы просто не использовать DefaultClient, зачем создавать собственный экземпляр клиента и какая в этом польза?
Если мы посмотрим на определение структуры http.Client, оно будет иметь следующие поля:
type Client struct { Transport RoundTripper CheckRedirect func(req *Request, via []*Request) error Jar CookieJar Timeout time.Duration }
Если мы хотим, мы можем установить свою собственную реализацию транспорта, мы можем контролировать, как обрабатывается перенаправление, передать cookie для сохранения в файл и передать их в следующий запрос или просто установить тайм-аут. Роль тайм-аута часто очень важна при создании HTTP-запросов. DefaultClient не устанавливает тайм-аут по умолчанию. Поэтому, если вредоносная служба хочет, она может заблокировать ваши запросы (и ваши goroutines) на неопределенный срок, вызывая хаос в вашем приложении. Настройка клиента дает нам больший контроль над отправкой запросов.
-
Golang: Работы с HTTP запросами часть 2