Golang实现Web表单文件上传到指定URL的方法
Golang实现Web表单文件上传到指定URL的方法 使用 Go 和 http.NewRequest,将 Web 表单以 multipart 模式接收到的文件转发到任意 URL 的最佳方法是什么?
1 回复
更多关于Golang实现Web表单文件上传到指定URL的方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go中实现将接收到的multipart表单文件转发到其他URL,可以通过以下方式处理:
package main
import (
"bytes"
"io"
"mime/multipart"
"net/http"
"os"
)
// 处理上传并转发文件
func uploadAndForwardHandler(w http.ResponseWriter, r *http.Request) {
// 解析multipart表单,限制大小为10MB
err := r.ParseMultipartForm(10 << 20)
if err != nil {
http.Error(w, "无法解析表单", http.StatusBadRequest)
return
}
// 获取文件
file, header, err := r.FormFile("file")
if err != nil {
http.Error(w, "无法获取文件", http.StatusBadRequest)
return
}
defer file.Close()
// 创建缓冲区存储文件数据
var buf bytes.Buffer
writer := multipart.NewWriter(&buf)
// 创建表单文件字段
part, err := writer.CreateFormFile("file", header.Filename)
if err != nil {
http.Error(w, "创建表单字段失败", http.StatusInternalServerError)
return
}
// 复制文件数据
_, err = io.Copy(part, file)
if err != nil {
http.Error(w, "复制文件数据失败", http.StatusInternalServerError)
return
}
// 添加其他表单字段(如果需要)
_ = writer.WriteField("key", "value")
// 关闭writer以完成multipart数据
writer.Close()
// 创建转发请求
targetURL := "https://目标URL/上传端点"
req, err := http.NewRequest("POST", targetURL, &buf)
if err != nil {
http.Error(w, "创建请求失败", http.StatusInternalServerError)
return
}
// 设置正确的Content-Type头部
req.Header.Set("Content-Type", writer.FormDataContentType())
// 发送请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
http.Error(w, "转发请求失败", http.StatusInternalServerError)
return
}
defer resp.Body.Close()
// 读取响应并返回给客户端
body, err := io.ReadAll(resp.Body)
if err != nil {
http.Error(w, "读取响应失败", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", resp.Header.Get("Content-Type"))
w.WriteHeader(resp.StatusCode)
w.Write(body)
}
// 流式传输版本,适用于大文件
func streamUploadHandler(w http.ResponseWriter, r *http.Request) {
// 解析multipart表单
reader, err := r.MultipartReader()
if err != nil {
http.Error(w, "无法创建multipart读取器", http.StatusBadRequest)
return
}
// 创建管道用于流式传输
pr, pw := io.Pipe()
writer := multipart.NewWriter(pw)
// 启动goroutine处理流式写入
go func() {
defer pw.Close()
defer writer.Close()
for {
part, err := reader.NextPart()
if err == io.EOF {
break
}
if err != nil {
pw.CloseWithError(err)
return
}
// 创建对应的表单部分
formPart, err := writer.CreatePart(part.Header)
if err != nil {
pw.CloseWithError(err)
return
}
// 复制数据
_, err = io.Copy(formPart, part)
part.Close()
if err != nil {
pw.CloseWithError(err)
return
}
}
}()
// 创建转发请求
targetURL := "https://目标URL/上传端点"
req, err := http.NewRequest("POST", targetURL, pr)
if err != nil {
http.Error(w, "创建请求失败", http.StatusInternalServerError)
return
}
req.Header.Set("Content-Type", writer.FormDataContentType())
// 发送请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
http.Error(w, "转发请求失败", http.StatusInternalServerError)
return
}
defer resp.Body.Close()
// 返回响应
io.Copy(w, resp.Body)
}
func main() {
http.HandleFunc("/upload", uploadAndForwardHandler)
http.HandleFunc("/stream-upload", streamUploadHandler)
http.ListenAndServe(":8080", nil)
}
对于更高效的内存使用,可以使用io.Pipe实现流式传输:
func forwardFileStream(sourceURL, targetURL string) error {
// 从源URL获取文件
resp, err := http.Get(sourceURL)
if err != nil {
return err
}
defer resp.Body.Close()
// 创建管道
pr, pw := io.Pipe()
writer := multipart.NewWriter(pw)
// 启动goroutine写入数据
go func() {
defer pw.Close()
defer writer.Close()
// 创建表单文件字段
part, err := writer.CreateFormFile("file", "filename.ext")
if err != nil {
pw.CloseWithError(err)
return
}
// 流式复制数据
_, err = io.Copy(part, resp.Body)
if err != nil {
pw.CloseWithError(err)
return
}
}()
// 创建转发请求
req, err := http.NewRequest("POST", targetURL, pr)
if err != nil {
return err
}
req.Header.Set("Content-Type", writer.FormDataContentType())
// 发送请求
client := &http.Client{}
forwardResp, err := client.Do(req)
if err != nil {
return err
}
defer forwardResp.Body.Close()
return nil
}
这些示例展示了如何使用http.NewRequest和multipart.Writer将接收到的文件转发到其他URL,第一个版本适合中小文件,第二个流式版本适合大文件传输。

