golang自动处理HTTP文件上传需求的中间件插件gulter的使用

Golang自动处理HTTP文件上传需求的中间件插件gulter的使用

Gulter是一个Go HTTP中间件,旨在简化Web应用程序的文件上传过程。它遵循标准的http.Handlerhttp.HandlerFunc接口,因此可以与任何框架或标准库路由器一起使用。

安装

go get -u -v github.com/adelowo/gulter

使用

假设您有一个HTML表单如下:

<form action="/" method="post" enctype="multipart/form-data">
  <input type="file" name="form-field-1" />
  <input type="file" name="form-field-2" />
</form>

要创建一个新的Gulter实例,可以这样做:

handler, _ := gulter.New(
  gulter.WithMaxFileSize(10<<20), // 设置最大文件大小为10MB
  gulter.WithValidationFunc( // 设置验证函数
   gulter.ChainValidators(gulter.MimeTypeValidator("image/jpeg", "image/png"), // 验证MIME类型
    func(f gulter.File) error {
     // 这里可以添加自定义的文件验证逻辑
     // 也可以只使用MimeTypeValidator或单独使用一个自定义验证器
     return nil
    })),
  gulter.WithStorage(s3Store), // 设置存储后端
 )

handler实际上是一个HTTP中间件,具有以下签名:Upload(keys ...string) func(next http.Handler) http.Handler。这里的keys是HTML表单中的输入名称,因此您可以将其链接到几乎任何HTTP路由器中。

标准HTTP路由器示例

package main

import (
 "fmt"
 "net/http"

 "github.com/adelowo/gulter"
 "github.com/adelowo/gulter/storage"
)

func main() {
 s3Store, err := storage.NewS3FromEnvironment(storage.S3Options{
  Bucket: "std-router",
 })
 if err != nil {
  panic(err.Error())
 }

 handler, err := gulter.New(
  gulter.WithMaxFileSize(10<<20), // 10MB
  gulter.WithStorage(s3Store),
 )

 mux := http.NewServeMux()

 // 上传表单字段名为"name"和"lanre"的所有文件
 mux.Handle("/", handler.Upload("name", "lanre")(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  fmt.Println("Uploaded file")

  // 获取所有上传的文件
  f, err := gulter.FilesFromContext(r)
  if err != nil {
   fmt.Println(err)
   return
  }

  // 获取表单字段"lanre"的上传文件
  ff, err := gulter.FilesFromContextWithKey(r, "lanre")
  if err != nil {
   fmt.Println(err)
   return
  }

  fmt.Printf("%+v", ff)

  for _, v := range f {
   fmt.Printf("%+v", v)
   fmt.Println()
  }
 })))

 http.ListenAndServe(":3300", mux)
}

Chi路由器和其他兼容HTTP处理程序示例

s3Store, err := storage.NewS3FromEnvironment(storage.S3Options{
  Bucket: "chi-router",
 })
 if err != nil {
  panic(err.Error())
 }

 handler := gulter.New(
  gulter.WithMaxFileSize(10<<20), // 10MB
  gulter.WithValidationFunc(gulter.ChainValidators(gulter.MimeTypeValidator("image/jpeg", "image/png"))),
  gulter.WithStorage(s3Store),
 )

 router := chi.NewMux()

 // 上传表单字段名为"form-field-1"和"form-field-2"的所有文件
 router.With(handler.Upload("form-field-1", "form-field-2")).Post("/", func(w http.ResponseWriter, r *http.Request) {
  fmt.Println("Uploaded file")

  f, err := gulter.FilesFromContext(r)
  if err != nil {
   fmt.Println(err)
   return
  }

  ff, err := gulter.FilesFromContextWithKey(r, "form-field-1") // 或者form-field-2
  if err != nil {
   fmt.Println(err)
   return
  }

  fmt.Printf("%+v", ff)

  for _, v := range f {
   fmt.Printf("%+v", v)
   fmt.Println()
  }
 })

API

虽然这个中间件会自动上传您的文件,但有时您需要有关上传文件的详细信息以显示给用户,这可能是组成图像URL或图像路径。要在HTTP处理程序中获取这些信息,您可以使用:

  • FilesFromContextWithKey: 检索指定输入名称的上传文件
  • FilesFromContext: 检索所有上传的文件

Gulter目前还提供了两种存储实现:

  • S3Store: 支持S3或任何兼容服务,如Minio、R2等
  • DiskStore: 使用本地文件系统支持的存储来上传文件
  • CloudinaryStore: 将文件上传到Cloudinary

常见问题

忽略多部分请求中不存在的键

有时,您配置的中间件键可能会因某种原因从前端删除,理想情况下,如果中间件无法在请求中找到配置的键,则会失败。要禁用此行为并忽略缺少的键,您可以使用WithIgnoreNonExistentKey(true)选项来防止中间件在缺少这些键时引发错误。

自定义错误响应

由于Gulter是一个运行的中间件,如果发现错误,它会向客户端返回错误,这可能与您现有的结构不匹配,因此要配置响应,请使用WithErrorResponseHandler。默认如下所示,可以用作定义您自己的模板。

errHandler ErrResponseHandler = func(err error) http.HandlerFunc {
  return func(w http.ResponseWriter, _ *http.Request) {
   w.Header().Set("Content-Type", "application/json")
   w.WriteHeader(http.StatusInternalServerError)
   fmt.Fprintf(w, `{"message" : "could not upload file", "error" : %s}`, err.Error())
  }
 }

编写自定义验证逻辑

有时,您可能有一些自定义逻辑来验证上传,在下面的示例中,我们根据上传文件的MIME类型限制上传的大小。

var customValidator gulter.ValidationFunc = func(f gulter.File) error {
 switch f.MimeType {
 case "image/png":
  if f.Size > 4096 {
   return errors.New("file size too large")
  }

  return nil

 case "application/pdf":
  if f.Size > (1024 * 10) {
   return errors.New("file size too large")
  }

  return nil
 default:
  return nil
 }
}

更多关于golang自动处理HTTP文件上传需求的中间件插件gulter的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang自动处理HTTP文件上传需求的中间件插件gulter的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang HTTP文件上传中间件gulter使用指南

gulter是一个轻量级的Golang中间件,用于简化HTTP文件上传处理。下面我将详细介绍如何使用gulter处理文件上传需求。

安装gulter

首先安装gulter包:

go get github.com/thewizardplusplus/go-gulter

基本用法

package main

import (
	"fmt"
	"log"
	"net/http"
	
	"github.com/thewizardplusplus/go-gulter"
)

func main() {
	// 创建gulter中间件实例
	uploadMiddleware := gulter.New(gulter.Config{
		// 上传文件存储目录
		UploadDir: "./uploads",
		// 允许的最大文件大小(字节)
		MaxFileSize: 10 << 20, // 10MB
		// 允许的MIME类型
		AllowedMimeTypes: []string{
			"image/jpeg",
			"image/png",
			"application/pdf",
		},
	})

	// 创建HTTP处理函数
	uploadHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// 从上下文中获取上传的文件信息
		files, ok := r.Context().Value(gulter.UploadedFilesContextKey).([]gulter.UploadedFile)
		if !ok {
			http.Error(w, "no files uploaded", http.StatusBadRequest)
			return
		}

		// 处理上传的文件
		for _, file := range files {
			fmt.Fprintf(w, "File uploaded: %s, Size: %d, MIME: %s\n", 
				file.Filename, file.Size, file.MimeType)
		}
	})

	// 应用中间件
	http.Handle("/upload", uploadMiddleware(uploadHandler))

	log.Println("Server started on :8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

高级配置

gulter提供了多种配置选项:

uploadMiddleware := gulter.New(gulter.Config{
	UploadDir: "./uploads",
	MaxFileSize: 5 << 20, // 5MB
	AllowedMimeTypes: []string{"image/*"}, // 允许所有图片类型
	FieldName: "custom_file_field", // 默认是"file"
	RandomFilename: true, // 生成随机文件名
	Overwrite: false, // 不允许覆盖已有文件
	Multiple: true, // 允许多文件上传
})

文件验证

你可以在处理函数中添加自定义验证:

uploadHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	files, ok := r.Context().Value(gulter.UploadedFilesContextKey).([]gulter.UploadedFile)
	if !ok {
		http.Error(w, "no files uploaded", http.StatusBadRequest)
		return
	}

	for _, file := range files {
		// 自定义验证逻辑
		if file.Size > 2<<20 { // 2MB
			http.Error(w, fmt.Sprintf("file %s is too large", file.Filename), http.StatusBadRequest)
			return
		}
		
		// 处理文件...
	}
})

错误处理

gulter会返回详细的错误信息:

uploadHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	if err, ok := r.Context().Value(gulter.UploadErrorContextKey).(error); ok {
		switch err {
		case gulter.ErrNoFileUploaded:
			http.Error(w, "请选择要上传的文件", http.StatusBadRequest)
		case gulter.ErrFileTooLarge:
			http.Error(w, "文件大小超过限制", http.StatusBadRequest)
		case gulter.ErrInvalidFileType:
			http.Error(w, "不支持的文件类型", http.StatusBadRequest)
		default:
			http.Error(w, "上传文件时出错", http.StatusInternalServerError)
		}
		return
	}
	
	// 正常处理...
})

完整示例

下面是一个完整的文件上传服务示例:

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	
	"github.com/thewizardplusplus/go-gulter"
)

func main() {
	// 确保上传目录存在
	if err := os.MkdirAll("./uploads", 0755); err != nil {
		log.Fatal(err)
	}

	// 配置gulter中间件
	uploadMiddleware := gulter.New(gulter.Config{
		UploadDir:        "./uploads",
		MaxFileSize:      5 << 20, // 5MB
		AllowedMimeTypes: []string{"image/jpeg", "image/png"},
		RandomFilename:   true,
	})

	// 上传处理函数
	uploadHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// 检查错误
		if err, ok := r.Context().Value(gulter.UploadErrorContextKey).(error); ok {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		// 获取上传的文件
		files, ok := r.Context().Value(gulter.UploadedFilesContextKey).([]gulter.UploadedFile)
		if !ok || len(files) == 0 {
			http.Error(w, "没有上传文件", http.StatusBadRequest)
			return
		}

		// 返回上传结果
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		for _, file := range files {
			fmt.Fprintf(w, `{"filename": "%s", "size": %d, "mime": "%s"}\n`,
				file.Filename, file.Size, file.MimeType)
		}
	})

	// 文件下载处理
	http.HandleFunc("/download/", func(w http.ResponseWriter, r *http.Request) {
		filename := r.URL.Path[len("/download/"):]
		http.ServeFile(w, r, "./uploads/"+filename)
	})

	// 上传路由
	http.Handle("/upload", uploadMiddleware(uploadHandler))

	// 静态文件服务
	fs := http.FileServer(http.Dir("./static"))
	http.Handle("/", fs)

	log.Println("Server started on :8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

总结

gulter是一个功能强大且易于使用的Golang文件上传中间件,它提供了:

  1. 文件大小限制
  2. MIME类型验证
  3. 多文件上传支持
  4. 随机文件名生成
  5. 详细的错误处理
  6. 简单的集成方式

通过合理配置,你可以轻松地为你的Golang Web应用添加安全可靠的文件上传功能。

回到顶部