前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Kratos实现go文件上传

Kratos实现go文件上传

原创
作者头像
衝鋒壹号
修改2023-11-18 11:08:03
9080
修改2023-11-18 11:08:03
举报
文章被收录于专栏:壹号的专栏壹号的专栏

前言

一般的项目都需要文件上传,但是Kratos的官方文档并没有写明如何实现,最近项目需要我就试着自己写了一下。

原理

服务器端:WEB服务器端程序接收到“multipart/form-data”类型的HTTP请求消息后,其核心和基本的编程工作就是读取请求消息中的实体内容,然后解析出每个分区的数据,接着再从每个分区中解析出描述头和主体内容部分。

实现

方式一:手动依赖注入

通过wire依赖注入生成文件,这时可以在生成的文件中编写wire_gen.go,直接写入路径和方法,跟简单gen编写简单HTTP一样,如下所示:

代码语言:go
复制
// main.go 创建 kratos 应用生命周期管理
func newApp(logger log.Logger, hs *http.Server, gs *grpc.Server, greeter *service.GreeterService) *kratos.App {
    pb.RegisterGreeterServer(gs, greeter)
    pb.RegisterGreeterHTTPServer(hs, greeter)
    route := httpServer.Route("/")
	route.POST("/v1/server/upload", greeter.Upload) // Upload方法没有在proto生成,无法使用gRPC请求
    return kratos.New(
        kratos.Name(Name),
        kratos.Version(Version),
        kratos.Logger(logger),
        kratos.Server(
            hs,
            gs,
        ),
    )
}

该方法可以实现文件上传,除了缺失了gRPC的功能,其他如鉴权等都不受影响。

方法二:手写proto文件

与正常的Kratos生成API方式一样,编写proto文件。

代码语言:go
复制
service UploadService {
  // 上传文件
  rpc UploadFile(stream File) returns(UploadResponse){
    option (google.api.http) = {
      post: "/v1/server/file/upload",
      body: "*",
    };
  }
}

message RemoveFileRsq {
  //文件路径
  string fileUrl = 1;
}

message File {
  bytes file = 1;
  string fileName = 2;
  int64 fileSize = 3;
  // 其他可自定义
}

编写完文件后跟平时生成文件不一致,此时不能急于使用命令去生产文件,而是需要手写代码,如下代码。

代码语言:go
复制
var _ = new(context.Context)
var _ = binding.EncodeURL

const _ = http.SupportPackageIsVersion1

type UploadFileServiceHTTPServer interface {
	UploadFileHttp(context.Context, *File, ...grpc.CallOption) (*UploadResponse, error)
}

func RegisterUploadFileServiceHTTPServer(s *http.Server, srv UploadFileServiceHTTPServer) {
	r := s.Route("/")
	r.POST("/v1/server/file/upload", _UploadService_SaveSite0_HTTP_Handler(srv))
}

func _UploadService_SaveSite0_HTTP_Handler(srv UploadFileServiceHTTPServer) func(ctx http.Context) error {
	return func(ctx http.Context) error {

		http.SetOperation(ctx, "/v1.system.UploadService/file/Upload")
		h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) {
			return srv.UploadFileHttp(ctx, req.(*File))
		})
		// 逻辑处理,取数据
        return ctx.Result(200, result)
    }
}

注意:这边生成文件以后也要在代码中实现方法处理后续逻辑,这边最好是将文件转换成bytes类型,传入实现方法。

再次使用命令生成proto里面的其他API即可,其逻辑代码如下:

代码语言:go
复制
func (s *SystemService) UploadFileHttp(ctx context.Context, reqFile *pb.File, opts ...grpc.CallOption) (*pb.UploadResponse, error) {
	log.Info("文件:%s,大小:%d, 存储:%s", reqFile.GetFileName(), reqFile.GetFileSize(), bucket)
	fileName := fmt.Sprintf("%s/%s", reqFile.Directory, reqFile.FileName)
	if reqFile.FileSize <= 0 {
		reqFile.FileSize = int64(len(reqFile.File))
	}
    fileName := fmt.Sprintf("%s/%s", reqFile.Directory, reqFile.FileName)
	if reqFile.FileSize <= 0 {
		reqFile.FileSize = int64(len(reqFile.File))
	}
	err := s.minio.Save(bucket, fileName, bytes.NewReader(reqFile.File), reqFile.FileSize) // 文件上传到minio
	if err != nil {
		log.Error(err.Error())
	}
	fileType := file.CheckFileType(reqFile.FileName)
	return &pb.UploadResponse{Url: fmt.Sprintf("/%v/%v", bucket, fileName), FileType: fileType}, nil
}

这里需要注意,因为上层已经将文件转换成bytes类型,这里无法取到文件名称,建议上传应该提前读取文件名字传入,也可随机重新生成文件名字,看业务需求!

该方法的优点就是支持gRPC,可以给其他服务调用。

总结

两个方法的差距在于是否支持gRPC调用,还有业务代码量,各位需要根据自己项目需求去选择合适的方法。

邀请人:程序员法医

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 原理
  • 实现
    • 方式一:手动依赖注入
      • 方法二:手写proto文件
      • 总结
      相关产品与服务
      微服务平台 TSF
      微服务平台(Tencent Service Framework,TSF)是一个围绕应用和微服务的 PaaS 平台,提供一站式应用全生命周期管理能力和数据化运营支持,提供多维度应用和服务的监控数据,助力服务性能优化。提供基于 Spring Cloud 和 Service Mesh 两种微服务架构的商业化支持。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档