3.7. 创建 File
Github: github.com/bigfile/bigfile
基本概要
如果非要将 Bigfile
中的 API
进行分类,可以分为两类,一类使用 APP
密钥签名,一类使用 Token
密钥签名,如果 Token
没有密钥,那就不用签名了。
需要注意的是,在 Bigfile
中,文件和目录我们都统称为 File
,所以 创建 File
既可以用来上传文件,也可以用来创建目录,而且您必须创建一个 Token
才能操作这些文件和目录。由于 Token
是有作用域的,所以一个 Token
只能在它的作用域下进行操作。
API
我们来看一下 API
的基本信息:
POST /api/bigfile/file/create
名称 | 类型 | 必填 | 描述 |
---|---|---|---|
token | string | yes | token 值 |
nonce | string | yes | 32 到 48 长度的随机字符串 |
path | string | yes | 文件存储路径,相对于 Token 路径 |
file | byte | no | 文件内容,不参与签名,最大:1MB |
sign | string | no | 参数签名,如果 Token 是有密钥的,那么它是必填的 |
hash | string | no | 上传的当前文件的 hash 值,基于 sha256 算法,用于校验,可不填 |
size | int | no | 上传的当前文件的 size ,单位:byte ,用于校验,可不填 |
overwrite | bool | no | 如果指定的路径存在文件,覆盖 |
rename | bool | no | 如果指定的路径存在文件,重命名 |
append | bool | no | 如果指定的路径存在文件,追加,常用于大文件上传 |
hidden | bool | no | 将文件置为隐藏,被隐藏的文件无法被下载 |
此 API
的 Content-Type
类型必须是:multipart/form-data
类型。
创建文件示例
package main
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
libHttp "net/http"
"os"
"github.com/bigfile/bigfile/databases/models"
"github.com/bigfile/bigfile/http"
)
func main() {
token := "49f92acd696260abba1bc4062d157199"
tokenSecret := "9bcac735fd7f25947a3909998420affa"
file, err := os.Open("/Users/fudenglong/Downloads/WechatIMG455.jpeg")
if err != nil {
fmt.Println(err)
return
}
for index := 0; ; index++ {
var (
err error
body = new(bytes.Buffer)
chunk = make([]byte, models.ChunkSize)
request *libHttp.Request
readCount int
formBodyWriter = multipart.NewWriter(body)
formFileWriter io.Writer
)
// 分片读取,每次读取 1MB
if readCount, err = file.Read(chunk); err != nil {
fmt.Println(err)
return
}
params := map[string]interface{}{
"token": token,
"path": "/profile/WechatIMG455.jpeg",
"nonce": models.RandomWithMd5(255),
}
if index == 0 {
params["overwrite"] = "1"
} else {
params["append"] = "1"
}
// 签名参数
params["sign"] = http.GetParamsSignature(params, tokenSecret)
for k, v := range params {
if err = formBodyWriter.WriteField(k, v.(string)); err != nil {
fmt.Println(err)
return
}
}
// 写入 request body
if formFileWriter, err = formBodyWriter.CreateFormFile("file", "random.bytes"); err != nil {
fmt.Println(err)
return
}
if _, err = formFileWriter.Write(chunk[:readCount]); err != nil {
fmt.Println(err)
return
}
if err = formBodyWriter.Close(); err != nil {
fmt.Println(err)
return
}
api := "https://127.0.0.1:10985/api/bigfile/file/create"
if request, err = libHttp.NewRequest(libHttp.MethodPost, api, body); err != nil {
fmt.Println(err)
return
}
// 设置请求头
request.Header.Set("Content-Type", formBodyWriter.FormDataContentType())
resp, err := libHttp.DefaultClient.Do(request)
if err != nil {
fmt.Println(err)
return
}
if bodyBytes, err := ioutil.ReadAll(resp.Body); err != nil {
fmt.Println(err)
return
} else {
fmt.Println(string(bodyBytes))
}
}
}
在这个例子中,我们上传了一个 4.7 MB
的文件,但是该接口每次仅限上传 1 MB
的文件,所以我们将文本分割成 1 MB
再去上传它。
而且,我们在上传第一个分片的时候声明如果该路径上的文件已经存在,那么就去覆盖它,随后的分片追加到该路径表的文件中。
需要注意的是,如果您选择如果在路径存在时重命名,那么您应该在第一个分片上传之后判断它,如果返回的文件和你指定的上传路径不一致,在追加随后的分片的时候应该使用第一个分片上传之后返回的路径。
这个例子在最后一次请求响应成功后会返回下面的结果:
{
"requestId":10020,
"success":true,
"errors":null,
"data":{
"ext":"jpeg",
"fileUid":"64c8a8ecd911630acf1dc26e8319f2dd",
"hash":"9536467bde347627e27634a77963105a045f624e290b0f2bbc342834abdd4593",
"hidden":0,
"isDir":0,
"path":"/images/png/profile/WechatIMG455.jpeg",
"size":4698744
}
}
fileUid
是一个重要的字段,是每个文件或者目录的唯一凭证,isDir=0
表示它不是一个目录,hash
表示整个文件的 hash 值,您可以用此值去验证文件的完整性。size
表示文件的大小,单位:byte
,1 MB = 1024 * 1024 byte
。
创建目录示例
package main
import (
"bytes"
"fmt"
"io/ioutil"
"mime/multipart"
libHttp "net/http"
"github.com/bigfile/bigfile/databases/models"
"github.com/bigfile/bigfile/http"
)
func main() {
var (
err error
body = new(bytes.Buffer)
request *libHttp.Request
token = "49f92acd696260abba1bc4062d157199"
tokenSecret = "9bcac735fd7f25947a3909998420affa"
formBodyWriter = multipart.NewWriter(body)
)
params := map[string]interface{}{
"token": token,
"path": "/profiles",
"nonce": models.RandomWithMd5(255),
}
params["sign"] = http.GetParamsSignature(params, tokenSecret)
for k, v := range params {
if err = formBodyWriter.WriteField(k, v.(string)); err != nil {
fmt.Println(err)
return
}
}
if err = formBodyWriter.Close(); err != nil {
fmt.Println(err)
return
}
api := "https://127.0.0.1:10985/api/bigfile/file/create"
if request, err = libHttp.NewRequest(libHttp.MethodPost, api, body); err != nil {
fmt.Println(err)
return
}
request.Header.Set("Content-Type", formBodyWriter.FormDataContentType())
resp, err := libHttp.DefaultClient.Do(request)
if err != nil {
fmt.Println(err)
return
}
if bodyBytes, err := ioutil.ReadAll(resp.Body); err != nil {
fmt.Println(err)
return
} else {
fmt.Println(string(bodyBytes))
}
}
这个请求之后将会得到如下的响应:
{
"requestId":10025,
"success":true,
"errors":null,
"data":{
"fileUid":"03ccc6c26ec7c3a0fe2be90c3f3882d0",
"hidden":0,
"isDir":1,
"path":"/images/png/profiles",
"size":0
}
}
isDir=1
表示它是一个目录,size
表示该目录下所有子文件以及子目录大小之和。
英文文档:bigfile.site
推荐文章: