gpt4 book ai didi

http - 使用 mime/multipart 上传会损坏文件

转载 作者:行者123 更新时间:2023-12-03 03:11:37 26 4
gpt4 key购买 nike

我写了一个服务器,有一个上传图片的路由。这是一个接收一些参数的表单:标题描述可见性图片。该页面还使用 Authentication header 。

func UploadPictureRoute(prv *services.Provider) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user, err := auth.ValidateRequest(prv, w, r)
if auth.RespondError(w, err) {
return
}

r.ParseMultipartForm(10 << 20) // 10 meg max

title := r.FormValue("title")
desc := r.FormValue("description")
visib := r.FormValue("visibility")
visibInt, err := strconv.Atoi(visib)
visibility := int8(visibInt) // Visibility can be either 0, 1, 2

if err != nil {
w.WriteHeader(http.StatusBadRequest)
}

file, _, err := r.FormFile("picture")
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
defer file.Close()

mimeType, _, err := mimetype.DetectReader(file) // Package gabriel-vasile/mimetype
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}

if !utils.IsValidMimetype(mimeType) { // Basically just comparing to image/png, image/jpg. Crashes here
w.WriteHeader(http.StatusBadRequest)
return
}

parentFolder := prv.PicturePath + "/" + strconv.FormatInt(*user.ID, 10) + "/"

_, err = os.Stat(parentFolder)
if os.IsNotExist(err) {
err = os.MkdirAll(parentFolder, os.ModePerm)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
}

pict := model.Picture{
Title: title,
Description: desc,
Creator: &user,
Visibility: visibility,
Ext: utils.GetExtForMimetype(mimeType),
}

pict, err = dal.CreatePicture(prv, pict)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}

outputFile, err := os.Create(parentFolder + strconv.FormatInt(*pict.ID, 10) + "." + pict.Ext)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
dal.DeletePicture(prv, pict)
}
defer outputFile.Close()

_, err = io.Copy(outputFile, file)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
// Responding
}
}

使用 Postman 效果很好,它可以正确上传文件,一切都按预期进行。

但是,我未能编写一个 go http 客户端来上传文件:

type uploadResponse struct {
URLID string
}

func main() {
filename := "filename.png"

file, err := os.Open(filename)
if err != nil {
fmt.Println(err)
}
defer file.Close()

// Just to be sure we're really at the start of the file
_, err = file.Seek(0, io.SeekStart)
if err != nil {
fmt.Println("Can't read the file")
return
}

mime, _, err := mimetype.DetectReader(file)
if err != nil {
fmt.Println("Can't read the file")
return
}

if !api.IsMimetypeAllowed(mime) { // Just check if it's a jpg/png/gif. This works on the client
fmt.Println("This filetype can't be uploaded to a Scinna server.")
fmt.Println("Please convert this file to jpeg, png or gif.")

return
}


body := &bytes.Buffer{}
writer := multipart.NewWriter(body)

title, _ := writer.CreateFormField("title")
title.Write([]byte("My picture title"))

desc, _ := writer.CreateFormField("description")
desc.Write([]byte("My picture description"))

visib, _ := writer.CreateFormField("visibility")
visib.Write([]byte("0"))

pict, _ := writer.CreateFormFile("picture", file.Name())
_, err = io.Copy(pict, file)

writer.Close()

r, err := http.NewRequest("POST", "https://myapi.local/pictures", body)
if err != nil {
panic(err)
}
r.Header.Add("Content-Type", writer.FormDataContentType())
r.Header.Add("Authorization", "Bearer "+config.Token)

client := &http.Client{}
client.Do(r)
}

此代码会导致服务器崩溃。图片的 mimetype 变为 application/octet-stream 并且图像标题已损坏(它仍然在某些编辑器中打开,但 EyesOfGnome 基本上表示该图片不是 JPG/PNG 文件,因为它可以'找不到开头的神奇数字)

如何修复HTTP go客户端才能成功上传图片?

最佳答案

mimetype.DetectReader(file) 的调用读取文件的一部分。对 _, err = io.Copy(pict, file) 的调用会读取文件的其余部分。要读取整个文件,请返回到调用 io.Copy 之前的偏移量 0。

文件在偏移量 0 处打开。调用 Open 后无需立即查找偏移量 0。

通过交换调用顺序来修复问题:

...

mime, _, err := mimetype.DetectReader(file)
if err != nil {
fmt.Println("Can't read the file")
return
}

// Rewind to the start of the file
_, err = file.Seek(0, io.SeekStart)
if err != nil {
fmt.Println("Can't read the file")
return
}

...

服务器也有类似的问题。检测类型后回退:

mimeType, _, err := mimetype.DetectReader(file) // Package gabriel-vasile/mimetype
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}

// Rewind to the start of the file
_, err = file.Seek(0, io.SeekStart)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}

关于http - 使用 mime/multipart 上传会损坏文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59028602/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com