Golang文件传输管理系统Bigfile http服务带证书验证使用

今天突然有个需求要搭建一个在线资源文件管理平台,发现Bigfile可以用来做后端服务,Bigfile 是使用golang开发的一个文件传输管理系统。

如何创建APP,启动http服务请参考使用文档:https://learnku.com/docs/bigfile/1.0 。

当启动好http服务后,第一步创建token,创建 Token 是接下来所有操作的开始,让我们先开看一下 API 参数。

POST /api/bigfile/token/create

nametyperequireddescription
appUidstringyesAPP UID
noncestringyes32 到 48 长度的随机字符串
signstringyes请求参数签名
pathstringnoToken 的作用域,默认为:/,可以理解为根目录
ipstringno限制当前 Token 仅能被使用的 IP 列表,多个 IP 逗号分隔
expiredAttimestampnoToken 失效时间,默认永久有效
secretstringnoToken 密钥,12 到 32 位,建议设置,默认为空
availableTimesintnoToken 可用次数,默认无限次数
readOnlyboolno限制此 Token 仅能被用于去下载文件

 

若启动服务使用了证书文件像下面方式启动:

bigfile http:start --cert-file server.pem --cert-key server.key

那么使用官方文档的例子可能出现如下错误:

x509: certificate signed by unknown authority

是因为使用 rpc:make-cert 生成的证书不被系统信任,这里有三种解决方案:

  1. 将证书加入到系统的可信任证书库中
  2. 在请求时选择不验证证书。
  3. 通过代码加载证书来加密或解密传输数据。

我使用的是第三种方式,具体代码如下:

创建一个tools.go文件包名为utils

package utils

import (
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
)
//封装返回一个*http.Client
func client(rootCa, rootKey string) *http.Client {
	var tr *http.Transport
	certs, err := tls.LoadX509KeyPair(rootCa, rootKey)
	if err != nil {
		fmt.Println("未找到证书文件")
		tr = &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		}
	} else {
		ca, err := x509.ParseCertificate(certs.Certificate[0])
		if err != nil {
			return &http.Client{Transport: tr}
		}
		pool := x509.NewCertPool()
		pool.AddCert(ca)

		tr = &http.Transport{
			TLSClientConfig: &tls.Config{RootCAs: pool},
		}

	}
	return &http.Client{Transport: tr}
}
//发送post请求
func WPost(url,  rootCa, rootKey ,body string ) ([]byte, error) {
	resp, err := client(rootCa, rootKey).Post(url,"application/x-www-form-urlencoded",strings.NewReader(body))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	b,err:=ioutil.ReadAll(resp.Body)
	if err!=nil{
		return nil,err
	}
	return b, nil
}
//封装Request包发送,用于后面上传文件
func WDo(rootCa,rootKey string,request *http.Request) ([]byte, error){
	resp,err:=client(rootCa,rootKey).Do(request)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	b,err:=ioutil.ReadAll(resp.Body)
	if err!=nil{
		return nil,err
	}
	return b, nil
}

创建实现方法文件function.go

package utils

import (
	"bytes"
	"fmt"
	"github.com/bigfile/bigfile/databases/models"
	"github.com/bigfile/bigfile/http"
	"io"
	"log"
	"mime/multipart"
	libHttp "net/http"
	"os"
	"time"
)
//MakeToken 创建token
func MakeToken(){
	appUid := "d972584eddc59247c322ca8b38782065"
	appSecret := "2VjGpzrmJQiJ"
	body := http.GetParamsSignBody(map[string]interface{}{
		"appUid":         appUid,
		"nonce":          models.RandomWithMD5(128),
		"path":           "/images/png",
		"expiredAt":      time.Now().AddDate(0, 0, 2).Unix(),
		"secret":         models.RandomWithMD5(44),
		"availableTimes": -1,
		"readOnly":       false,
	}, appSecret)

	b,e:= WPost(
		"https://127.0.0.1:10985/api/bigfile/token/create",
		"server/server.pem",//你自己的.pem文件路径
		"server/server.key",//你自己的.key文件路径
        body)
	if e!=nil{
		log.Fatal(e)
	}
	fmt.Println(string(b))
}
//UpFile 上传文件
func UpFile(){
	token := "399f28a3c964e137536cda4517c5eaa6"
	tokenSecret := "be3041191baad445a0a4c852334b1c2e"

	file, err := os.Open("./client/img/timg.jpg")//要上传的文件路径
	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/timg.jpg",//上传保存的文件路径
			"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:=WDo("server/server.pem",//证书文件路径
			"server/server.key",//证书文件路径
			request)
		if err != nil {
			fmt.Println(err)
			return
		}
		fmt.Println(string(resp))
	}
}

//CreateFileLink 创建文件下载链接
func CreateFileLink(token,fileUid,tokenSecret string,openInBrowser bool) string{
	body := http.GetParamsSignBody(map[string]interface{}{
		"token": token,
		"fileUid":  fileUid,
		"nonce": models.RandomWithMD5(255),
		"openInBrowser":true,
	}, tokenSecret)
	return "https://127.0.0.1:10985/api/bigfile/file/read?"+body
}

创建main.go

func main() {
	//创建token
	utils.MakeToken()
	//上传文件
	utils.UpFile()

	//获取文件下载地址
	fmt.Println(utils.CreateFileLink("399f28a3c964e137536cda4517c5eaa6",
		"fdc8a68d7e2578ba201467d65653305d",
		"be3041191baad445a0a4c852334b1c2e",
		true))
}
//创建token
utils.MakeToken()

返回以下结果:

{
	"requestId": 10033,
	"success": true,
	"errors": null,
	"data": {
		"availableTimes": -1,
		"expiredAt": 1575731179,
		"ip": null,
		"path": "/images/png",
		"readOnly": 0,
		"secret": "75d45a4e2b388f302282d2e034456bed",
		"token": "d79f17581056b889e3b872ea679a784d"
	}
}
//上传文件
utils.UpFile()

 上传文件返回如下结果:

{
	"requestId": 10034,
	"success": true,
	"errors": null,
	"data": {
		"ext": "jpg",
		"fileUid": "e3098acd4b62196abca649b64fb6415c",
		"hash": "d57b252a571319793bf38a313b88e2ae65e73e8d444ae1eb3224b9e72a121f5b",
		"hidden": 0,
		"isDir": 0,
		"path": "/images/png/profile/timg.jpg",
		"size": 88428
	}
}
//获取文件下载地址
fmt.Println(utils.CreateFileLink("399f28a3c964e137536cda4517c5eaa6",
	"fdc8a68d7e2578ba201467d65653305d",
	"be3041191baad445a0a4c852334b1c2e",
	true))

获取文件下载链接返回一个地址,可以直接再浏览器上打开: 

https://127.0.0.1:10985/api/bigfile/file/read?fileUid=fdc8a68d7e2578ba201467d65653305d&nonce=f142f5c160e4563c118a46d1c6315a18&openInBrowser=true&token=399f28a3c964e137536cda4517c5eaa6&sign=088d73b3d87c3e15ac66802ee368fd91

其它操作类似,不作描述。注意工具类中使用了Bigfile的一下现成的方法,所以需要引用Bigfile的包,若用go mod 代码如下:

module bigfile

go 1.13

require github.com/bigfile/bigfile v1.0.10

然后 go mod tidy加载包。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
鉴于你提供的资料中没有明确的问题,我将基于提供的引用内容为你提供一个回答。 引用中提到了一个使用golang实现的文件服务,包括上传和下载功能的服务器端和客户端。这个文件服务可以用于在客户端显示图片列表,并且保护文件服务器的地址不被暴露出来。具体实现的代码可以参考引用中的示例,其中使用了`os.Args`来获取当前可执行程序的路径,并通过`http.Handle()`和`http.ListenAndServe()`开启了一个文件服务器监听在8088端口。所以,如果你想实现一个golang文件服务器,你可以参考这个示例代码。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [golang 文件服务器](https://blog.csdn.net/weixin_31211703/article/details/119474361)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [golang文件服务器的两种方式(可以访问任何目录)](https://blog.csdn.net/n_fly/article/details/115495514)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值