upload

package
v1.0.4-Realize Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 28, 2022 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

* 包upload包含了对http文件上传的封装

expect:be sure to finish! author:KercyLAN create at:2020-2-29 22:51 todo:待优化,断点续传待实现

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type FailedFiles

type FailedFiles map[string]error

上传失败的文件集合结构描述。

type FileGroup

type FileGroup map[string][]*multipart.FileHeader

对请求中FileGroup的描述。

func (FileGroup) Each

func (slf FileGroup) Each(groupName string, hook func(i int, fileHeader *multipart.FileHeader))

遍历所有groupName组下的成员反馈到hook中。

func (FileGroup) EachAll

func (slf FileGroup) EachAll(
	hook func(groupName string, groupIndex int, fileHeader *multipart.FileHeader) error,
	failHook func(groupName string, groupIndex int, fileName string, fileSize int64, err error) bool) error

遍历所有的FileHeader反馈到hook中

当hook返回的err为value存在多个的时候的时候,整个遍历将终止。

当hook返回的err为其他如文件创建失败等错误的时候,会进入下一个循环,并且将信息传入failHook中。

当failHook返回true,则表示直接终止遍历。

func (FileGroup) Exist

func (slf FileGroup) Exist(groupName string) bool

检查groupName这个组是否存在。

func (FileGroup) GroupLen

func (slf FileGroup) GroupLen(groupName string) int

返回groupName组的成员数量。

type FileMeta

type FileMeta struct {
	// contains filtered or unexported fields
}

HTTP上传的文件的文件元信息。

func NewFileMeta

func NewFileMeta(name string, size int64) *FileMeta

构建一个完备的文件元信息。

func (*FileMeta) GetExt

func (slf *FileMeta) GetExt() string

获取文件的拓展名。

func (*FileMeta) GetHash

func (slf *FileMeta) GetHash() string

获取文件的hash值。

func (*FileMeta) GetId

func (slf *FileMeta) GetId() string

获取文件id。

func (*FileMeta) GetName

func (slf *FileMeta) GetName() string

获取文件的真实名称。

func (*FileMeta) GetNode

func (slf *FileMeta) GetNode() cloud.Node

获取文件所对应的节点信息。

func (*FileMeta) GetSize

func (slf *FileMeta) GetSize() int64

获取文件占用的空间大小。

func (*FileMeta) GetStorageName

func (slf *FileMeta) GetStorageName() string

获取该文件在文件系统中的存储的文件名。

func (*FileMeta) GetUploadAt

func (slf *FileMeta) GetUploadAt() time.Time

获取文件的上传时间。

func (*FileMeta) IsFastUpload

func (slf *FileMeta) IsFastUpload() bool

检查这个文件是否是快速上传的。

type FileUploadReceiver

type FileUploadReceiver struct {
	// contains filtered or unexported fields
}

文件上传接收器

用于对HTTP POST请求中的文件上传操作进行处理, 由于文件上传接收器是支持云端应用的,所以所有文件均以UUID的形式在磁盘存储。

在默认不配置storageDir的情况下,默认的存储路径为"./storage"目录下,而一些临时文件则会存储在"./storage/temp"目录下。

由于FileUploadReceiver在设计之初便考虑其需要极强的适应性,因此在非特殊场景需求的情况下,通常维护FileUploadReceiver的单例即可。

在使用FileUploadReceiver过程中,客户端不需要做过多的处理,便可以实现诸如下方的各项功能:

  • 普通的单个或多个文件上传;
  • 单个或多个文件的快速上传(秒传);
  • 普通上传和快速上传混合使用(如文件1进行普通上传,文件2进行快速上传);
  • 普通的文件分块上传;
  • 快速上传模式下的分块上传;
  • 文件传输过程劫持篡改检查;
  • 多文件上传是否要求必须全部上传成功的控制;
  • 对上传的文件大小进行限制;

func New

func New(storageDir ...string) (*FileUploadReceiver, error)

构建一个FileUploadReceiver实例

当storageDir未设置的情况下,FileUploadReceiver会将所有的文件存储在默认的“./storage”目录下。

如果需要改变这一情况,可以在构建FileUploadReceiver的时候传入一个目录路径作为参数。 如果这个目录不存在的话,FileUploadReceiver会自行进行创建,如果参数存在多个的话,那么只取第一个。

注意:存储文件需要依赖于节点信息,应该在main包的init函数下调用“application.Initialize()”函数进行应用程序初始化。

func (*FileUploadReceiver) Dispose

func (slf *FileUploadReceiver) Dispose(request *http.Request) ([]*FileMeta, FailedFiles, error)

处理文件上传请求

在使用上传处理功能的时候应该注意以下两点:

  • fileGroup表示如“<input name="group_name" type="file">”这个html元素中的name属性,相同name属性的视为同一个fileGroup;
  • valueGroup表示如“<input name="group_name" type="hidden" value="1">”这个html元素中的name属性,相同name属性的视为同一个valueGroup。

FileUploadReceiver在处理请求时候会有几种情况:

  • 情况1:当获取到的valueGroup不包含任何成员的时候,表明为普通的文件上传;
  • 情况2:当获取到的fileGroup和valueGroup包含1个成员的时候,表明为快速上传,即秒传; ·同时,在满足情况2和已经设置过SetCompletenessCheckHandler的情况下,会对文件的完整性进行检查。
  • 情况3:当获取到的fileGroup和valueGroup的成员数不是1:1的时候,会返回error。

秒传情况下的请求中,保证每个文件的name属性和表示其hash的POST参数name属性相同。

应该保证如下方这样的form结构。

<form enctype="multipart/form-data" action="_URL_" method=POST>
	<input name="file1" type="file">
	<input name="file1" type="hidden" value="file1-hash">
	<input name="file2" type="file">
	<input name="file2" type="hidden" value="file2-hash">
</form>

func (*FileUploadReceiver) DisposePart

func (slf *FileUploadReceiver) DisposePart(request *http.Request) (string, error)

处理分块文件上传请求

分块上传时FileUploadReceiver会读取请求中的一个文件和一个文本内容来作为块进行上传。

在HTML中,无需为file input以及hidden input设置特定的name属性,FileUploadReceiver对此不做任何约束。

在使用分块上传的时候应该注意一下几点:

  • 分块上传依赖于pratProcessor,在即将开始一个分块上传任务之前,应当调用FileUploadReceiver.NewPartTask来创建一个分块任务;
  • 分块上传应当为多次请求来进行每个块的上传,比如三个块则发起三次请求;
  • 在分块上传中,每个请求仅允许存在一个文件和一个文本,而且文本的格式必须符合“hash(string);sort(int):size(int64)”,这个文本表示了最终得到的文件hash应该是什么,这个块在这个文件中的什么位置,这个最终文件的文件大小应该是多大;
  • 分块上传的每一块文件上传均支持快速上传的特性,客户端无需做特殊处理,服务端仅需要使用过FileUploadReceiver.SetFastUploadHandler即可;

不用担心会因为多次请求而造成每个块分散开来,FileUploadReceiver.NewPartTask会为他们之间建立关系;

为了避免内存泄漏,在每一块文件大小超过一个特定的阈值的时候,则这个分块文件会被保存在本地。

当一个文件的分块即存在大于这个阈值和小于这个阈值的情况,他们会分散在内存和磁盘中,最后会进行合并。

如果需要调整这个值,可以使用FileUploadReceiver.SetPartUploadBufferSize函数来进行配置。

func (*FileUploadReceiver) DisposePartMerge

func (slf *FileUploadReceiver) DisposePartMerge(hash string, fileName string) (*FileMeta, error)

合并分块上传的文件

在合并的时候partProcessor会对这个hash所标记的合并任务进行检查。

当所有分块没有完全上传完毕的时候,则会返回一个error,里面会补充一些提示和进度信息。

func (FileUploadReceiver) GetPartUploadSuccess

func (slf FileUploadReceiver) GetPartUploadSuccess(hash string) []int

返回特定hash的分块上传任务已上传的分块序号。

func (FileUploadReceiver) IsFinish

func (slf FileUploadReceiver) IsFinish(hash string) bool

检查指定hash的任务是否已经完成。

func (FileUploadReceiver) NewPartTask

func (slf FileUploadReceiver) NewPartTask(hash string, partNumber int)

创建一个分块上传任务

由于分块上传是由多个文件组成一个文件,所以hash表示了他们共同指向的文件hash。

具体的分块数量由partNumber决定。

func (*FileUploadReceiver) SetCompletenessCheckHandler

func (slf *FileUploadReceiver) SetCompletenessCheckHandler(handler func(data []byte) string)

设置文件完整性检查处理函数

文件完整性检查处理函数用于检查文件是否在上传过程中被篡改。

使用某种加密方式加密数据后返回一个计算得出的hash值即可用作完整性检查,通常建议CRC、MD5或者SHA256加密。

使用文件完整性检查的情况下,所消耗的内存会因为要将文件内容存储下来而变为文件占用空间大小 + readMaxMemory的值,效率也会有所降低。

func (*FileUploadReceiver) SetFailureAllowed

func (slf *FileUploadReceiver) SetFailureAllowed(allowOr bool)

设置是否不允许存在文件上传失败的情况

在多文件上传的过程中,如果这个值为true,那么当存在一个文件上传失败的情况,则所有文件上传均视为失败。 当这个值为false的时候,如果有文件上传失败则会对其进行记录,并在上传结束后将成功上传的文件FileMeta和 上传失败的文件信息进行返回。

func (*FileUploadReceiver) SetFastUploadHandler

func (slf *FileUploadReceiver) SetFastUploadHandler(handler func(hash string) *FileMeta)

设置快速上传查询函数

快速上传查询被用于快速上传功能中,所设置的handler需要实现查询传入的hash是否已经在之前被上传过。 这个hash通常是由客户端使用和服务端相同的计算方式得到的,服务端在上传文件的时候,如果这个hash没有被上传过, 那么应该执行普通的上传流程,并将上传后的结果使用数据库等方式进行存储,而handler便是在存储结果中查阅是否拥 有这个记录,并返回一个FileMeta。

当返回的FileMeta不为空的时候,视为已上传,则进行快速上传操作。

func (*FileUploadReceiver) SetFileMaxSize

func (slf *FileUploadReceiver) SetFileMaxSize(fileMaxSize int64)

设置上传的文件最大允许的内存空间占用大小

上传文件中,如果这个fileMaxSize大于0,将会对文件大小进行校验。

当fileMaxSize小于0的时候,将会设置为0。

func (*FileUploadReceiver) SetPartFileMaxSize

func (slf *FileUploadReceiver) SetPartFileMaxSize(fileMaxSize int64)

设置分块上传的文件最大允许的内存空间占用大小

上传文件中,如果这个fileMaxSize大于0,将会对文件大小进行校验。

当fileMaxSize小于0的时候,将会设置为0。

func (*FileUploadReceiver) SetPartUploadBufferSize

func (slf *FileUploadReceiver) SetPartUploadBufferSize(partUploadBufferSize int64)

设置分块上传每个块的缓冲区大小

当上传的块占用空间大小小于这个值的情况下,则会直接将其数据存储在内存中以加快效率。

当上传的块占用空间大小大于这个值的情况下,会将其数据存储到storageDir的临时目录中。

合理的设置这个值可以防止由于内存申请过大造成的内存溢出问题, 同时也可以在性能和稳定性之间保持一个平衡。

func (*FileUploadReceiver) SetReadMaxMemory

func (slf *FileUploadReceiver) SetReadMaxMemory(maxMemory int64)

设置ReadForm最大的内存数量

默认golang会预留10MB的内存供给非文件的数据。如果不需要这个预留的内存,则在maxMemory中减去10 * 1024 * 1024即可,不过这样做并不建议。

当所读取的内容大小超出了这个值,则会缓存在临时文件中,效率将会有所降低。

func (*FileUploadReceiver) SetSaveFileBufferSize

func (slf *FileUploadReceiver) SetSaveFileBufferSize(size int64)

设置每次读取文件缓冲区大小

当文件大小大于这个值的时候,会分为多次进行读取。

当文件大小小于这个值的时候,会一次性进行读取。

当这个值过大的情况下会导致一次性申请的内存过多,造成内存浪费。

type ValueGroup

type ValueGroup map[string][]string

对请求中ValueGroup的描述。

func (ValueGroup) Each

func (slf ValueGroup) Each(groupName string, hook func(i int, value string))

遍历所有groupName组下的成员反馈到hook中。

func (ValueGroup) Exist

func (slf ValueGroup) Exist(groupName string) bool

检查groupName这个组是否存在。

func (ValueGroup) GroupLen

func (slf ValueGroup) GroupLen(groupName string) int

返回groupName组的成员数量。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL