英文:
How can I receive an uploaded file using a Golang net/http server?
问题
我正在玩Mux和net/http
。最近,我试图创建一个简单的服务器,其中包含一个端点来接受文件上传。
以下是我目前的代码:
server.go
package main
import (
"fmt"
"github.com/gorilla/mux"
"log"
"net/http"
)
func main() {
router := mux.NewRouter()
router.
Path("/upload").
Methods("POST").
HandlerFunc(UploadCsv)
fmt.Println("Starting")
log.Fatal(http.ListenAndServe(":8080", router))
}
endpoint.go
package main
import (
"fmt"
"net/http"
)
func UploadFile(w http.ResponseWriter, r *http.Request) {
err := r.ParseMultipartForm(5 * 1024 * 1024)
if err != nil {
panic(err)
}
fmt.Println(r.FormValue("fileupload"))
}
我认为问题的关键在于在UploadFile
函数中获取请求的主体。当我运行以下cURL命令时:
curl http://localhost:8080/upload -F "fileupload=@test.txt" -vvv
我得到一个空的响应(预期的结果;我没有将其打印到ResponseWriter
),但是我只在运行服务器的提示符下得到一个新的(空的)行,而不是请求主体。
我是以多部分形式发送文件的(根据使用-F
而不是-d
在cURL中的含义),cURL的详细输出显示发送了502字节:
$ curl http://localhost:8080/upload -F "fileupload=@test.txt" -vvv
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> POST /upload HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.51.0
> Accept: */*
> Content-Length: 520
> Expect: 100-continue
> Content-Type: multipart/form-data; boundary=------------------------b578878d86779dc5
>
< HTTP/1.1 100 Continue
< HTTP/1.1 200 OK
< Date: Fri, 18 Nov 2016 19:01:50 GMT
< Content-Length: 0
< Content-Type: text/plain; charset=utf-8
<
* Curl_http_done: called premature == 0
* Connection #0 to host localhost left intact
在Go中,使用net/http
服务器接收以多部分表单数据形式上传的文件的正确方法是什么?
英文:
I'm playing around with Mux and net/http
. Lately, I'm trying to get a simple server with one endpoint to accept a file upload.
Here's the code I've got so far:
server.go
package main
import (
"fmt"
"github.com/gorilla/mux"
"log"
"net/http"
)
func main() {
router := mux.NewRouter()
router.
Path("/upload").
Methods("POST").
HandlerFunc(UploadCsv)
fmt.Println("Starting")
log.Fatal(http.ListenAndServe(":8080", router))
}
endpoint.go
package main
import (
"fmt"
"net/http"
)
func UploadFile(w http.ResponseWriter, r *http.Request) {
err := r.ParseMultipartForm(5 * 1024 * 1024)
if err != nil {
panic(err)
}
fmt.Println(r.FormValue("fileupload"))
}
I think I've narrowed the issue down to actually retrieving the body from the request inside UploadFile
. When I run this cURL command:
curl http://localhost:8080/upload -F "fileupload=@test.txt" -vvv
I get an empty response (as expected; I'm not printing to the ResponseWriter
), but I just get a new (empty) line printed at the prompt where I'm running the server, instead of the request body.
I'm sending the file as multipart (AFAIK, implied by using -F
rather than -d
in cURL), and cURL's verbose output is showing 502 bytes sent:
$ curl http://localhost:8080/upload -F "fileupload=@test.txt" -vvv
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> POST /upload HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.51.0
> Accept: */*
> Content-Length: 520
> Expect: 100-continue
> Content-Type: multipart/form-data; boundary=------------------------b578878d86779dc5
>
< HTTP/1.1 100 Continue
< HTTP/1.1 200 OK
< Date: Fri, 18 Nov 2016 19:01:50 GMT
< Content-Length: 0
< Content-Type: text/plain; charset=utf-8
<
* Curl_http_done: called premature == 0
* Connection #0 to host localhost left intact
What's the proper way to receive files uploaded as multipart form data using a net/http
server in Go?
答案1
得分: 51
以下是翻译好的内容:
这是一个快速示例
func ReceiveFile(w http.ResponseWriter, r *http.Request) {
r.ParseMultipartForm(32 << 20) // 限制最大输入长度!
var buf bytes.Buffer
// 在你的情况下,file 将是 fileupload
file, header, err := r.FormFile("file")
if err != nil {
panic(err)
}
defer file.Close()
name := strings.Split(header.Filename, ".")
fmt.Printf("文件名 %s\n", name[0])
// 将文件数据复制到缓冲区
io.Copy(&buf, file)
// 处理文件内容...
// 我通常会定义一个结构体并将其解组为结构体,但这只是一个示例
contents := buf.String()
fmt.Println(contents)
// 如果需要再次使用缓冲区,我会重置它
// 这样可以减少在更复杂的项目中的内存分配
buf.Reset()
// 做其他事情
// 例如写入头部
return
}
希望对你有帮助!
英文:
Here's a quick example
func ReceiveFile(w http.ResponseWriter, r *http.Request) {
r.ParseMultipartForm(32 << 20) // limit your max input length!
var buf bytes.Buffer
// in your case file would be fileupload
file, header, err := r.FormFile("file")
if err != nil {
panic(err)
}
defer file.Close()
name := strings.Split(header.Filename, ".")
fmt.Printf("File name %s\n", name[0])
// Copy the file data to my buffer
io.Copy(&buf, file)
// do something with the contents...
// I normally have a struct defined and unmarshal into a struct, but this will
// work as an example
contents := buf.String()
fmt.Println(contents)
// I reset the buffer in case I want to use it again
// reduces memory allocations in more intense projects
buf.Reset()
// do something else
// etc write header
return
}
答案2
得分: 21
你应该使用FormFile
而不是FormValue
:
file, fileHeader, err := r.FormFile("fileupload")
defer file.Close()
// 复制示例
f, err := os.OpenFile("./downloaded", os.O_WRONLY|os.O_CREATE, 0666)
defer f.Close()
io.Copy(f, file)
英文:
You should use FormFile
instead of FormValue
:
file, fileHeader, err := r.FormFile("fileupload")
defer file.Close()
// copy example
f, err := os.OpenFile("./downloaded", os.O_WRONLY|os.O_CREATE, 0666)
defer f.Close()
io.Copy(f, file)
答案3
得分: 11
这是我编写的一个函数,用于帮助我上传文件。你可以在这里查看完整版本。如何在Golang中上传文件
package helpers
import (
"io"
"net/http"
"os"
)
// 这个函数返回保存在数据库中的文件名,或者如果出现错误则返回错误
func FileUpload(r *http.Request) (string, error) {
// ParseMultipartForm将请求体解析为multipart/form-data
r.ParseMultipartForm(32 << 20)
file, handler, err := r.FormFile("file") // 从表单数据中获取文件
if err != nil {
return "", err
}
defer file.Close() // 完成后关闭文件
// 这是我们想要存储文件的路径
f, err := os.OpenFile("/pathToStoreFile/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
return "", err
}
// 将文件复制到目标路径
io.Copy(f, file)
return handler.Filename, nil
}
英文:
Here a function i wrote to help me in uploading my files.You can check the full version here . How to upload files in golang
package helpers
import (
"io"
"net/http"
"os"
)
// This function returns the filename(to save in database) of the saved file
// or an error if it occurs
func FileUpload(r *http.Request) (string, error) {
// ParseMultipartForm parses a request body as multipart/form-data
r.ParseMultipartForm(32 << 20)
file, handler, err := r.FormFile("file") // Retrieve the file from form data
if err != nil {
return "", err
}
defer file.Close() // Close the file when we finish
// This is path which we want to store the file
f, err := os.OpenFile("/pathToStoreFile/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
return "", err
}
// Copy the file to the destination path
io.Copy(f, file)
return handler.Filename, nil
}
1: https://kenyaappexperts.com/blog/how-to-upload-files-in-go-step-by-step/ "How to upload files in Golang"
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论