DevGang
Авторизоваться

Golang: Работы с HTTP запросами часть 3

В предыдущих статьях мы разобрались как отправлять GET/POST запросы и рассмотрели как сделать настройку модуля Client для отправки запросов. В этой статье мы рассмотрим как предавать файлы средствами net/http.

Для загрузки файлов при отправке HTTP-запроса нам нужно использовать пакет mime/multipart с пакетом net/http. Сначала мы увидим пример кода, а затем поясним его, чтобы понять, что мы делаем. 

func MakeRequest() {

	// Открываем файл
	file, err := os.Open("name.txt")
	if err != nil {
		log.Fatalln(err)
	}
	// Закрываем файл по завершению
	defer file.Close()

	// Буфер для хранения нашего тела запроса в виде байтов
	var requestBody bytes.Buffer

	// Создаем писателя
	multiPartWriter := multipart.NewWriter(&requestBody)

	// Инициализируем поле
	fileWriter, err := multiPartWriter.CreateFormFile("file_field", "name.txt")
	if err != nil {
		log.Fatalln(err)
	}

	// Скопируйте содержимое файла в поле
	_, err = io.Copy(fileWriter, file)
	if err != nil {
		log.Fatalln(err)
	}

	// Заполняем остальные поля
	fieldWriter, err := multiPartWriter.CreateFormField("normal_field")
	if err != nil {
		log.Fatalln(err)
	}

	_, err = fieldWriter.Write([]byte("Value"))
	if err != nil {
		log.Fatalln(err)
	}

	// Закрываем запись данных
	multiPartWriter.Close()

	// Создаем объект реквеста 
	req, err := http.NewRequest("POST", "https://httpbin.org/post", &requestBody)
	if err != nil {
		log.Fatalln(err)
	}
	// Получаем и устанавливаем тип контента
	req.Header.Set("Content-Type", multiPartWriter.FormDataContentType())

	// Отправляем запрос
	client := &http.Client{}
	response, err := client.Do(req)
	if err != nil {
		log.Fatalln(err)
	}

	var result map[string]interface{}

	json.NewDecoder(response.Body).Decode(&result)

	log.Println(result)
}

Итак, что мы здесь делаем?

  • Сначала мы открываем файл, который хотим загрузить. В нашем случае я создал файл с именем «name.txt», который просто содержит мое имя.
  • Мы создаем bytes.Buffer для хранения тела запроса, который мы передадим позже с нашим http.Request.
  • Мы создаем объект multipart.Writer и передаем указатель на наш файл bytes.Buffer.
  • Мы создаем поле файла и копируем его содержимое. Затем мы создаем нормальное поле и записываем в него «Value».
  • После того, как мы добавили наши данные, мы вызываем метод Close для объекта multiPartWriter.
  • Мы создаем новый POST запрос, как мы видели раньше. Мы передали bytes.Buffer, который мы создали как тело запроса. Тело теперь содержит данные формы нескольких полей, написанные с помощью пакета mime/multipart.
  • Отправляем запрос как и ранее. Но мы устанавливаем тип контента, вызывая multiPartWriter.FormDataContentType() - который обеспечивает правильный тип контента.
  • Мы декодируем ответ от httpbin и проверяем вывод.

Всегда закрывать тело ответа

Вот урок, который я усвоил. Когда мы делаем HTTP-запрос, мы получаем ответ и ошибку. Мы можем залениться и решать не проверять ошибки или не закрывать тело ответа (как в приведенных выше примерах). И это в последствие может вызвать много проблем. Если мы не закрываем тело ответа, соединение может оставаться открытым и вызывать утечку ресурсов. Но если ошибка не равна нулю, то в случае ошибки ответ может быть равен нулю. Таким образом, мы не можем просто сделать defer resp.Body.Close(). Мы должны проверить ошибку, а затем закрыть тело ответа.

client := http.DefaultClient
resp, err := client.Do(req)
if err != nil {
    return nil, err
}
defer resp.Body.Close()

Всегда использовать таймаут

Попробуйте использовать свой собственный клиент http и установите тайм-аут. Не настраивая тайм-аут вы можете блокировать соединение и goroutine и, следовательно, вызывать хаос. Итак, сделайте что-нибудь вроде этого:

timeout := time.Duration(5 * time.Second)
client := http.Client{
    Timeout: timeout,
}
client.Get(url)
#Golang
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу