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
Bigfile 中文文档
关于 LearnKu
推荐文章: