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