Skip to main content

文件上传

单文件

  1. 通过POSTform/data 方法选择文件
  2. golang获取POST/PUT方法的FormFile(key) (file,err)获取到文件
  3. 通过SaveUploadFile保存文件 SaveUploadFile(file, path) err
  4. file 文件, 通过POST/PUT方法上传的, 通过content.FormFIle()接收
  5. path 保存的路径与文件名
userGroup.POST("/upload", func(context *gin.Context) {
file, _ := context.FormFile("file")
err := context.SaveUploadedFile(file, "./upload/"+file.Filename)
if err != nil {
panic(err)
}
fmt.Println(file.Filename)
context.JSON(http.StatusOK, gin.H{
"msg": "OK",
})
})

前后端上传示例: 前端

const upload = (e: any) => {
console.log(e.target.files)
const formData = new FormData()
formData.append('file', e.target.files[0], e.target.files[0].name)
fetch('http://localhost:4000/upload', {
method: 'POST',
body: formData,
})
.then((res) => {
if (!res.ok){
throw new Error('上传失败')
}
return res.json()
})
.then(res => {
console.log(res.json())
})
.catch(err => {
console.error(err)
})
}

export default function Home () {

return (
<main>

<label>
<input hidden accept='image/*' type='file'
onChange={ (event: ChangeEvent<HTMLInputElement>) => upload(event) } />
</label>

</main>
)
}

Golang

package main

import (
"fmt"
"github.com/gin-gonic/gin"
"log"
"net/http"
)

func main() {
server := gin.Default()
server.Use(cors())
server.POST("/upload", func(context *gin.Context) {
file, _ := context.FormFile("file")
err := context.SaveUploadedFile(file, "./upload/1.jpg")
if err != nil {
panic(err)
}
fmt.Println(file.Filename)
context.JSON(http.StatusOK, gin.H{
"msg": "OK",
})
})

err := server.Run(":4000")
if err != nil {
return
}
}

func cors() gin.HandlerFunc {
return func(c *gin.Context) {
method := c.Request.Method
origin := c.Request.Header.Get("Origin") //请求头部
if origin != "" {
//接收客户端发送的origin (重要!)
c.Writer.Header().Set("Access-Control-Allow-Origin", origin)
//服务器支持的所有跨域请求的方法
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
//允许跨域设置可以返回其他子段,可以自定义字段
c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session")
// 允许浏览器(客户端)可以解析的头部 (重要)
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers")
//设置缓存时间
c.Header("Access-Control-Max-Age", "172800")
//允许客户端传递校验信息比如 cookie (重要)
c.Header("Access-Control-Allow-Credentials", "true")
//
//c.Header("Content-Type", "application/json")
}

//允许类型校验
if method == "OPTIONS" {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization") //自定义 Header
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT")
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
c.Header("Access-Control-Allow-Credentials", "true")
c.AbortWithStatus(http.StatusNoContent)
}

defer func() {
if err := recover(); err != nil {
log.Printf("Panic info is: %v", err)
}
}()
c.Next()
}
}

上传文件至Minio

package service

import (
"github.com/gin-gonic/gin"
"im/api/oss"
"im/utils"
"log"
"net/http"
"os"
"path/filepath"
)

func Upload(c *gin.Context) {
file, err := c.FormFile("file")
if err != nil {
c.String(http.StatusBadRequest, "get form err: %s", err.Error())
log.Fatalln("存储文件失败" + err.Error())
}

dst := "./uploads/"
if err := c.SaveUploadedFile(file, dst+file.Filename); err != nil {
log.Fatalln("存储文件失败" + err.Error())
}

// 上传文件至minio
bucketName := os.Getenv("MINIO_BUCKET") // Minio存储桶名
uploadDir, _ := utils.GetPath("/uploads/", file.Filename) // 待上传的文件路径
uploadDirToLinux := filepath.FromSlash(uploadDir) // 转成Minio的服务器路径, 本机部署在Linux,通过FromSlash替换成/路径
uploadInfo, uploadErr := oss.UploadFile(bucketName, file.Filename, uploadDirToLinux)
if uploadErr != nil {
log.Fatalln("上传文件失败:", err)
}

if err != nil {
c.AbortWithStatusJSON(http.StatusOK, gin.H{
"message": "上传文件至文件存储服务器失败:" + err.Error(),
"body": nil,
"code": http.StatusInternalServerError,
})
return
}
c.JSON(http.StatusOK, gin.H{
"message": "上传文件至文件存储服务器成功",
"body": uploadInfo,
"code": http.StatusOK,
})
}

func UploadFile(bucketName, filename, filepath string) (minio.UploadInfo, error) {
// 初使化minio client对象。
MinioClient, err := minio.New(os.Getenv("MINIO_URL"), &minio.Options{
Creds: credentials.NewStaticV4(os.Getenv("MINIO_ACCESS_KEY"), os.Getenv("MINIO_SECRET_KEY"), ""),
Secure: false,
})
if err != nil {
log.Fatalln("初始化Minio客户端失败" + err.Error())
}
uploadInfo, uploadErr := MinioClient.FPutObject(
context.TODO(),
bucketName,
filename,
filepath,
minio.PutObjectOptions{
ContentType: "application/zip",
})
if uploadErr != nil {
log.Fatalln("上传文件失败:", err)
}
return uploadInfo, nil
}

参考

  1. MDN
  2. 掘金