GoLang通过POST请求发送文件

huangapple go评论91阅读模式
英文:

GoLang send file via POST request

问题

我是你的中文翻译助手,以下是翻译好的内容:

我是Go语言的新手,我想创建一个用于文件上传的REST API Web服务器...

所以我在主函数(文件上传)中遇到了问题,通过POST请求将文件上传到我的服务器...

我有以下代码来调用上传函数:

router.POST("/upload", UploadFile)

这是我的上传函数:

func UploadFile(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
    io.WriteString(w, "Upload files\n")
    postFile(r.Form.Get("file"), "/uploads")
}

func postFile(filename string, targetUrl string) error {
    bodyBuf := &bytes.Buffer{}
    bodyWriter := multipart.NewWriter(bodyBuf)

    // 这一步非常重要
    fileWriter, err := bodyWriter.CreateFormFile("file", filename)
    if err != nil {
        fmt.Println("error writing to buffer")
        return err
    }

    // 打开文件句柄
    fh, err := os.Open(filename)
    if err != nil {
        fmt.Println("error opening file")
        return err
    }

    // 复制文件内容
    _, err = io.Copy(fileWriter, fh)
    if err != nil {
        panic(err)
    }

    bodyWriter.FormDataContentType()
    bodyWriter.Close()

    return err
}

但是我在/upload/目录中看不到任何上传的文件...

那么我做错了什么?

附注:我得到了第二个错误 error opening file,所以我认为文件上传或从UploadFile函数获取文件有问题,我是对的吗?如果是的话,我该如何将文件从这个函数传递到postFile函数?

英文:

I am new in GoLang language, and I want to create REST API WebServer for file uploading...

So I am stuck in main function (file uploading) via POST request to my server...

I have this line for calling upload function

router.POST("/upload", UploadFile)

and this is my upload function:

func UploadFile( w http.ResponseWriter, r *http.Request, _ httprouter.Params ) {
	io.WriteString(w, "Upload files\n")
	postFile( r.Form.Get("file"), "/uploads" )
}

func postFile(filename string, targetUrl string) error {
	bodyBuf := &bytes.Buffer{}
	bodyWriter := multipart.NewWriter(bodyBuf)

	// this step is very important
	fileWriter, err := bodyWriter.CreateFormFile("file", filename)
	if err != nil {
		fmt.Println("error writing to buffer")
		return err
	}

	// open file handle
	fh, err := os.Open(filename)
	if err != nil {
		fmt.Println("error opening file")
		return err
	}

	//iocopy
	_, err = io.Copy(fileWriter, fh)
	if err != nil {
		panic(err)
	}

	bodyWriter.FormDataContentType()
	bodyWriter.Close()

	return err

}

but I can't see any uploaded files in my /upload/ directory...

So what am I doing wrong?

P.S I am getting second error => error opening file, so I think something wrong in file uploading or getting file from UploadFile function, am I right? If yes, than how I can teancfer or get file from this function to postFile function?

答案1

得分: 4

multipart.Writer 生成多部分消息,这不是你想用来接收客户端文件并将其保存到磁盘的工具。

假设你正在从客户端(例如浏览器)上传文件,使用的是 Content-Type: application/x-www-form-urlencoded,你应该使用 FormFile 而不是 r.Form.GetFormFile 返回一个 *multipart.File 值,其中包含客户端发送的文件内容,你可以使用 io.Copy 或其他方法将该内容写入磁盘。

英文:

The multipart.Writer generates multipart messages, this is not something you want to use for receiving a file from a client and saving it to disk.

Assuming you're uploading the file from a client, e.g. a browser, with Content-Type: application/x-www-form-urlencoded you should use FormFile instead of r.Form.Get which returns a *multipart.File value that contains the content of the file the client sent and which you can use to write that content to disk with io.Copy or what not.

答案2

得分: 3

os.Open将打开一个文件,由于文件不存在,你将会得到一个错误。
使用os.Create代替,它将创建一个新文件并打开它。(参考:https://golang.org/pkg/os/#Open)

func Open

func Open(name string) (*File, error)

Open函数打开一个指定名称的文件进行读取。如果成功,返回的文件对象可以用于读取;关联的文件描述符的模式为O_RDONLY。如果出现错误,将会是*PathError类型的错误。

func Create

func Create(name string) (*File, error)

Create函数使用0666模式(在umask之前)创建一个指定名称的文件,如果文件已经存在,则截断它。如果成功,返回的文件对象可以用于I/O操作;关联的文件描述符的模式为O_RDWR。如果出现错误,将会是*PathError类型的错误。

编辑

创建了一个新的处理程序作为示例:
还使用了OpenFile,如此处所述:https://stackoverflow.com/questions/45541656/golang-send-file-via-post-request/45541764?noredirect=1#comment78043634_45541764

func Upload(w http.ResponseWriter, r *http.Request) {
    io.WriteString(w, "上传文件\n")

    file, handler, err := r.FormFile("file")
    if err != nil {
        panic(err) //请不要这样做
    }
    defer file.Close()

    // 复制示例
    f, err := os.OpenFile(handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
    if err != nil {
        panic(err) //请不要这样做
    }
    defer f.Close()
    io.Copy(f, file)
}
英文:

os.Open will open a file, since the file doesn't exist you will get an error.
Use os.Create instead it will create a new file and open it. (ref: https://golang.org/pkg/os/#Open)

> func Open

> func Open(name string) (*File, error)

> Open opens the named file for
> reading. If successful, methods on the returned file can be used for
> reading; the associated file descriptor has mode O_RDONLY. If there is
> an error, it will be of type *PathError.

> func Create
>
> func Create(name string) (*File, error)
>
> Create creates the named file with mode 0666 (before umask),
> truncating it if it already exists. If successful, methods on the
> returned File can be used for I/O; the associated file descriptor has
> mode O_RDWR. If there is an error, it will be of type *PathError.

EDIT

Made a new handler as an example:
And also using OpenFile as mentioned by: https://stackoverflow.com/questions/45541656/golang-send-file-via-post-request/45541764?noredirect=1#comment78043634_45541764

func Upload(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "Upload files\n")

	file, handler, err := r.FormFile("file")
	if err != nil {
		panic(err) //dont do this
	}
	defer file.Close()

	// copy example
	f, err := os.OpenFile(handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		panic(err) //please dont
	}
	defer f.Close()
	io.Copy(f, file)
	
}

huangapple
  • 本文由 发表于 2017年8月7日 15:40:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/45541656.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定