Метод http.Client.Do

Метод http.Client.Do выполняет HTTP-запрос, представленный объектом http.Request, и возвращает объект http.Response содержащий ответ от сервера. Первым параметром метод принимает указатель на структуру http.Request, которую необходимо создать с помощью функции http.NewRequest или http.NewRequestWithContext. Метод позволяет полностью контролировать процесс выполнения запроса, включая заголовки, тело и таймауты.

Синтаксис

goclient.Do(req)

где client - объект типа http.Client, req - указатель на http.Request. Метод возвращает два значения: указатель на http.Response и ошибку.

Пример

Давайте выполним GET-запрос к тестовому API и выведем код ответа и тело ответа:

gopackage main

import (
  "fmt"
  "io"
  "net/http"
)

func main() {
  client := &http.Client{}
  req, err := http.NewRequest("GET", "https://httpbin.org/get", nil)
  if err != nil {
    panic(err)
  }

  res, err := client.Do(req)
  if err != nil {
    panic(err)
  }
  defer res.Body.Close()

  fmt.Println("Status:", res.StatusCode)
  body, _ := io.ReadAll(res.Body)
  fmt.Println(string(body))
}

Пример

Давайте выполним POST-запрос с отправкой JSON-данных и добавим заголовок Content-Type:

gopackage main

import (
  "bytes"
  "fmt"
  "io"
  "net/http"
)

func main() {
  client := &http.Client{}
  jsonData := []byte(`{"name": "John", "age": 30}`)
  
  req, err := http.NewRequest(
    "POST",
    "https://httpbin.org/post",
    bytes.NewBuffer(jsonData),
  )
  if err != nil {
    panic(err)
  }
  
  req.Header.Set("Content-Type", "application/json")
  
  res, err := client.Do(req)
  if err != nil {
    panic(err)
  }
  defer res.Body.Close()
  
  body, _ := io.ReadAll(res.Body)
  fmt.Println(string(body))
}

Пример

Давайте обработаем ошибки, которые могут возникнуть при выполнении запроса, включая сетевые ошибки и ошибки статуса ответа:

gopackage main

import (
  "fmt"
  "net/http"
)

func main() {
  client := &http.Client{}
  req, err := http.NewRequest("GET", "https://invalid-url.example", nil)
  if err != nil {
    fmt.Println("Error creating request:", err)
    return
  }
  
  res, err := client.Do(req)
  if err != nil {
    fmt.Println("Error executing request:", err)
    return
  }
  defer res.Body.Close()
  
  if res.StatusCode != http.StatusOK {
    fmt.Println("Unexpected status:", res.StatusCode)
    return
  }
  
  fmt.Println("Request successful")
}

Пример

Давайте используем метод http.Client.Do с контекстом для управления таймаутами и отменой запроса:

gopackage main

import (
  "context"
  "fmt"
  "net/http"
  "time"
)

func main() {
  client := &http.Client{}
  ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  defer cancel()
  
  req, err := http.NewRequestWithContext(
    ctx,
    "GET",
    "https://httpbin.org/delay/3",
    nil,
  )
  if err != nil {
    panic(err)
  }
  
  res, err := client.Do(req)
  if err != nil {
    fmt.Println("Error:", err)
    return
  }
  defer res.Body.Close()
  
  fmt.Println("Status:", res.StatusCode)
}

Результат выполнения кода:

go"Status: 200"

Смотрите также

  • метод http.Client.Get,
    который выполняет GET-запрос более простым способом
  • метод http.Client.Post,
    который выполняет POST-запрос с отправкой данных
  • метод http.Client.Head,
    который выполняет HEAD-запрос без получения тела
  • функцию http.NewRequestWithContext,
    которая создает запрос с поддержкой контекста