kratos中实现http文件上传下载需区分微服务中转与minio直传:上传须手动注册路由、解析multipart表单并校验文件;推荐minio预签名url直传以规避服务压力;下载需流式响应防止oom。

在Kratos框架中实现HTTP协议下的文件上传与下载功能,需绕过gRPC默认不支持二进制流的限制,直接操作HTTP请求体和响应体,同时兼顾MinIO预签名直传等生产级部署需求。这要求你明确区分“微服务中转上传”和“前端直传MinIO”两种路径,避免将大文件经由Kratos服务中转造成内存溢出或超时。
手动注册HTTP上传路由并解析multipart/form-data
第一步:在internal/server/http.go中为上传接口显式注册POST路由,不依赖proto生成(因为proto无法描述文件流):
route.POST("/v1/upload", greeter.Upload)
第二步:在internal/service/greeter.go中编写Upload方法,使用ctx.Request().MultipartForm()获取表单数据。注意必须先调用ParseMultipartForm(32 设置最大内存缓存(此处32MB),否则<code>MultipartForm()会返回http.ErrNotMultipart错误。
第三步:从form.File中取出*multipart.FileHeader,调用header.Open()获得io.ReadCloser,再用io.Copy写入目标路径或MinIO客户端。这一步不可跳过Open()直接读header,否则会读到空内容。
第四步:返回JSON响应,包含fileUrl等字段。若需支持多文件,遍历form.File["files"]即可,但要单独校验每个FileHeader.Size防止恶意超大文件上传。
通过MinIO预签名URL实现前端直传(推荐)
该方式适用于生产环境,文件不经过Kratos服务,由前端直传MinIO,彻底规避服务端带宽与内存压力。
方法一:调用MinIO PresignedPutObject生成PUT链接
在MinIO客户端封装函数,传入bucketName、objectName(建议含时间戳与随机后缀防覆盖)和过期时间(如24 * time.Hour),返回*url.URL和map[string]string(含X-Amz-Algorithm等签名头)。
方法二:调用PresignedPostPolicy生成HTML表单所需参数
此方式兼容旧版浏览器,返回presignedURL string + formData map[string]string(含key、policy、signature等)。前端用<form method="POST" action="xxx"></form>提交,无需JS干预。
【注意】objectName必须严格校验格式,禁止用户控制完整路径,否则可写入任意bucket目录导致越权
实现文件下载(流式响应)
第一步:定义HTTP GET路由,例如route.GET("/v1/download/{filename}", greeter.Download),其中{filename}需做URL编码安全过滤,拒绝../等路径穿越字符。
第二步:在Download方法中,根据filename拼出MinIO中对象的objectName,调用minioClient.GetObject(ctx, bucket, objectName, opts)获取object。
第三步:设置HTTP响应头:ctx.Response().Header().Set("Content-Disposition", "attachment; filename="+filename),并设"Content-Type"为application/octet-stream或根据扩展名推断(如.pdf→application/pdf)。
第四步:用io.Copy(ctx.Response(), object)将MinIO对象流直接写入HTTP响应体。这一步必须用io.Copy而非bytes.Buffer全量加载,否则1GB文件会OOM。











