Поврежденный файл изображения в golang api image download - PullRequest
0 голосов
/ 04 февраля 2020

Я создаю простой API тестирования в golang для загрузки и загрузки файлов изображений (PNG, JPEG, JPG):

/ pi c [POST] для загрузки изображения и сохранения его в папка; / pi c [GET] для загрузки изображения на клиент.

Я успешно собрал / pi c [POST], и изображение успешно загружено в файл сервера. И я могу открыть файл в папке хранения. (Как на windows локальном сервере, так и на сервере Ubuntu)

Однако, когда я собрал / pi c [GET] для загрузки картинки, я могу загрузить файл на клиент (мой компьютер ), но загруженный файл каким-то образом поврежден, поскольку при попытке открыть его с помощью другого средства просмотра изображений, такого как галерея или Photoshop, появляется сообщение «Похоже, мы не поддерживаем этот формат файла». Похоже, загрузка не удалась.

Результат почтальона: enter image description here

Открытие файла в галерее: enter image description here Любые идеи почему это происходит и как мне это исправить?

Код golang для загрузки pi c выглядит следующим образом (без обработки ошибок):

func PicDownload(w http.ResponseWriter, r *http.Request){

   request := make(map[string]string)
   reqBody, _ := ioutil.ReadAll(r.Body)
   err = json.Unmarshal(reqBody, &request)
   // Error handling

   file, err := os.OpenFile("./resources/pic/" + request["filename"], os.O_RDONLY, 0666)
   // Error handling

   buffer := make([]byte, 512)
   _, err = file.Read(buffer)
   // Error handling

   contentType := http.DetectContentType(buffer)

   fileStat, _ := file.Stat()

   // Set header
   w.Header().Set("Content-Disposition", "attachment; filename=" + request["filename"])
   w.Header().Set("Content-Type", contentType)
   w.Header().Set("Content-Length", strconv.FormatInt(fileStat.Size(), 10))

   // Copying the file content to response body
   io.Copy(w, file)

   return
}

1 Ответ

1 голос
/ 04 февраля 2020

Когда вы читаете первые 512 байт из файла, чтобы определить тип содержимого, указатель основного потока файла перемещается вперед на 512 байт. При последующем вызове io.Copy чтение продолжается с этой позиции.

Существует два способа исправить это.

Первый - это позвонить file.Seek(0, io.SeekStart) до вызова io.Copy(). Это поместит указатель обратно в начало файла. Это решение требует наименьшего количества кода, но подразумевает считывание одних и тех же 512 байт из файла дважды, что приводит к некоторым издержкам.

Второе решение - создать буфер, содержащий весь файл, используя buffer := make([]byte, fileStat.Size() и используя этот буфер как для вызова http.DetectContentType(), так и для записи вывода (запишите его с помощью w.Write(buffer) вместо использования io.Copy(). Этот подход имеет возможную обратную сторону загрузки всего файла в память сразу, что не идеально для очень большие файлы (io.Copy использует куски по 32 КБ вместо загрузки всего файла).

Примечание. Как упоминал Питер в комментарии, вы должны гарантировать, что пользователи не смогут пройти через вашу файловую систему, разместив ../../ или что-то в качестве имени файла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...