cpp

Отправка файла методом POST

Отправка файла также осуществляется методом POST. Процесс отправки выглядит следующим образом:

POST /index.php HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:32.0)
Accept: text/html, application/xml;q=0.9,*/*;q=0.8
Content-Type: multipart/form-data; boundary=метка
Content-Length: длина запроса

--метка
Content-Disposition: form-data; name="имя поля"; filename="имя файла"
Content-Type: text/plain

Текст файла
--метка--

В заголовке Content-Type указывается значение multipart/form-data. Параметр boundary задает текстовую метку, которая будет отмечать начало и конец данных. В теле сообщения перед меткой указываются два символа тире, а после метки — символ перевода строки. Если метка является последней, то после нее указываются два символа тире. Между метками размещаются строки с заголовками Content-Disposition и Content-Type, а после пустой строки идет содержимое файла. Таких блоков, ограниченных метками, может быть несколько, следовательно, за один раз можно отправить сразу несколько файлов или других данных.

Отправить запрос методом POST позволяет функция Post() из пакета net/http. Запрос можно отправить по протоколам HTTP и HTTPS. Формат функции:

http.Post(url string, contentType string,
          body io.Reader) (resp *http.Response, err error)

Функция в качестве первого параметра принимает URL-адрес в виде строки, в качестве второго — значение заголовка Content-Type, а в качестве третьего — экземпляр структуры, реализующей интерфейс Reader. Данные без кодирования отправляются в теле запроса, а не в составе URL-адреса.

Обратите внимание: мы не имеем возможности формировать заголовки запроса, поэтому используются значения заголовков по умолчанию. Например, значением заголовка User-Agent (название нашего робота) будет Go-http-client/1.1.

Функция возвращает два значения. Через первое возвращаемое значение доступен указатель на объект структуры Response, с помощью которого можно обработать результат. Через второе возвращаемое значение доступен объект ошибки или значение nil, если операция выполнена успешно.

Чтобы можно было потренироваться и наглядно увидеть процесс загрузки файла, изменим содержимое файла C:\xampp\htdocs\index.php следующим образом:

<?php
if (isset($_FILES['file_name'])) {
   if ($_FILES['file_name']['error'] == 0 && 
       $_FILES['file_name']['size'] > 0) {
      $path = "C:\\xampp\\htdocs\\test_file.txt";
      if (@move_uploaded_file($_FILES['file_name']['tmp_name'], $path)) {
         echo "Файл успешно сохранен. Путь " . $path;
      }
      else {
         echo "Не удалось переместить файл";
      }
   }
   else {
      echo "Ошибка №" . $_FILES['file_name']['error'];
   }
}
else {
   echo "Нет файла";
}
?>

Теперь отправим этому скрипту файл (листинг 19.4).

Листинг 19.4. Отправка файла

package main

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

func main() {
   b, err := os.ReadFile(`C:\book\file.txt`)
   if err != nil {
      fmt.Println(err)
      return
   }
   buf := bytes.NewBuffer([]byte("------------------11487310131944\n"))
   buf.Write([]byte("Content-Disposition: form-data; " +
                    "name=\"file_name\"; filename=\"file.txt\"\n"))
   buf.Write([]byte("Content-Type: text/plain\n\n"))
   buf.Write(b)
   buf.Write([]byte("\n------------------11487310131944--"))
   u := "http://localhost/index.php"
   contentType := "multipart/form-data; " +
                  "boundary=----------------11487310131944"
   resp, err := http.Post(u, contentType, buf)
   if err != nil {
      fmt.Println(err)
      return
   }
   defer resp.Body.Close()
   if resp.StatusCode >= 300 {
      fmt.Println("Статус:", resp.Status)
      return
   }
   fmt.Println("Статус:", resp.Status)
   body, err := io.ReadAll(resp.Body)
   if err != nil {
      fmt.Println(err)
      return
   }
   fmt.Println(string(body))
}

Если все сделано правильно, то отобразится сообщение:

Статус: 200 OK
Файл успешно сохранен. Путь C:\xampp\htdocs\test_file.txt

С помощью функции Post() можно также отправить данные формы, хотя для этого удобнее воспользоваться функцией PostForm() (см. разд. 19.7). Давайте изменим содержимое файла C:\xampp\htdocs\index.php следующим образом:

<?php
print_r($_POST);
?>

Теперь выполним запрос методом POST и обработаем результат (листинг 19.5).

Листинг 19.5. Отправка запроса методом POST

package main

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

func main() {
   m := url.Values{}
   m.Add("color1", "красный")
   m.Add("color2", "белый")
   buf := bytes.NewBuffer([]byte(m.Encode()))
   u := "http://localhost/index.php"
   contentType := "application/x-www-form-urlencoded"
   resp, err := http.Post(u, contentType, buf)
   if err != nil {
      fmt.Println(err)
      return
   }
   defer resp.Body.Close()
   if resp.StatusCode >= 300 {
      fmt.Println("Статус:", resp.Status)
      return
   }
   fmt.Println("Статус:", resp.Status)
   body, err := io.ReadAll(resp.Body)
   if err != nil {
      fmt.Println(err)
      return
   }
   fmt.Println(string(body))
}

Если все сделано правильно, то отобразится сообщение:

Статус: 200 OK
Array
(
    [color1] => красный
    [color2] => белый
)

Учебник Go (Golang)
Учебник Go (Golang) в формате PDF

Помощь сайту

ЮMoney (Yandex-деньги): 410011140483022

ПАО Сбербанк:
Счет: 40817810855006152256
Реквизиты банка:
Наименование: СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК
Корреспондентский счет: 30101810500000000653
БИК: 044030653
КПП: 784243001
ОКПО: 09171401
ОКОНХ: 96130
Скриншот реквизитов

cpp