Kratos 本身不拦截文件上传大小,超限由 HTTP 服务器层(如 Nginx、Gin)或反向代理控制;Nginx 默认 client_max_body_size=1MB,Gin 默认 MaxMultipartMemory=32MB,Go net/http.Server 无内置限制但需同步调大超时与内存参数。

Kratos 本身不拦截或限制文件上传大小,超限问题实际发生在 HTTP 服务器层(如 Gin、Go-HTTP)或反向代理(如 Nginx),必须在对应层级配置,而非 Kratos 代码里加判断。
为什么 Kratos 里加 if file.Size > 100 * 1024 * 1024 没用
因为 Kratos 的 HTTP handler(比如你写的 Upload 方法)只有在请求体完整到达后才会被调用。如果客户端发了一个 2GB 的文件,而你的 Gin 服务器或 Nginx 已经在读取请求体中途就因超限断连,那 Kratos 根本收不到任何数据——ctx.Request.MultipartForm 都会是 nil,甚至直接返回 413 错误,你的业务逻辑压根没机会执行。
- Nginx 默认
client_max_body_size是 1MB,超过就直接 413,Kratos 完全无感 - Gin 默认不限制,但若启用了
MaxMultipartMemory(默认 32MB),超了会 panic 或报错http: request body too large - Kratos 的
http.Server底层用的是标准net/http.Server,它自身没有上传大小控制开关
Gin 层必须显式配置 MaxMultipartMemory
如果你用的是 Kratos 默认集成的 Gin(常见于 http.NewServer),必须在初始化时传入自定义的 http.Server 并设置 MaxMultipartMemory,否则默认 32MB 就会触发 http: request body too large。
示例:
srv := http.NewServer(
http.Address(":8000"),
http.Middleware(
middleware.Recovery(),
),
http.Handler(func() http.Handler {
r := gin.Default()
r.MaxMultipartMemory = 512 << 20 // 512MB,单位是字节
r.POST("/v1/upload", uploadHandler)
return r
}()),
)- 这个值必须小于 Go 进程可用内存,否则上传大文件时可能 OOM
- 设为
0表示不限制内存使用(危险,不推荐) - 该配置只影响 multipart/form-data 解析阶段,不影响流式读取(如
ctx.Request.Body)
真正可靠的大文件方案:绕过内存解析,用流式读取 + 预签名 URL
对 >100MB 的文件,别依赖 ctx.Request.FormFile 或 MultipartForm。应直接读 ctx.Request.Body,边读边写入 MinIO 或本地临时文件,并配合预签名 URL 实现直传。
- Kratos handler 中用
io.Copy或分块io.ReadFull接收原始 body,避免一次性加载进内存 - 前端先调
/v1/presign获取 MinIO 预签名 PUT URL(由 Kratos 调minio.Client.PresignedPutObject生成) - 前端用
XMLHttpRequest或fetch直传到该 URL,完全不经过 Kratos 微服务 - 这样 Kratos 只处理元数据和鉴权,不碰文件本体,彻底规避大小限制和内存压力
容易被忽略的关键点
很多人以为改了 Kratos 的 handler 就能控制上传大小,其实真正的瓶颈在三个地方:Nginx 的 client_max_body_size、Gin 的 MaxMultipartMemory、以及 Go net/http.Server 的 ReadTimeout/WriteTimeout —— 大文件上传慢,超时比大小更容易先杀死请求。这些都得同步调大,且要保持链路一致(比如 Nginx timeout > Gin timeout > Go HTTP timeout)。


















