使用NestJS-MinIO-Client上传文件时遇Socket Hang Up问题求助
解决NestJS MinIO客户端长时间运行后Socket Hang Up问题
看起来你遇到的这个socket hang up错误,在Nginx反向代理+跨服务器Docker部署的场景里挺典型的。结合你的代码和架构,我帮你梳理下核心原因和对应的解决办法:
核心原因分析
这个错误本质是客户端与MinIO服务器之间的TCP连接被意外断开,但客户端仍尝试复用已失效的连接。具体诱因通常有这几个:
- Nginx反向代理会主动回收长时间空闲的连接,如果超时设置过短,旧连接失效后客户端没感知到,就会报错。
nestjs-minio-client底层依赖的minio-js默认连接池配置可能不够完善,长时间运行后失效连接堆积,导致新请求拿不到可用连接。- 跨服务器Docker容器之间的网络连接可能存在隐性超时,进一步加剧连接失效的问题。
具体解决方案
1. 调整Nginx反向代理的超时配置
先修改Nginx的代理配置,延长超时时间并开启长连接,避免Nginx主动断开空闲连接:
server { # 你的其他Nginx配置 location / { proxy_pass http://你的MinIO服务器地址:9000; # 延长各类超时时间,和后续客户端/MinIO配置保持一致(这里设为5分钟) proxy_connect_timeout 300s; proxy_send_timeout 300s; proxy_read_timeout 300s; # 开启HTTP/1.1长连接,避免频繁创建新连接 proxy_http_version 1.1; proxy_set_header Connection ""; # 可选:传递真实IP,方便MinIO日志排查 proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
修改完后重启Nginx生效:nginx -s reload
2. 优化MinIO客户端的连接池配置
在NestJS的MinIO模块注册时,添加自定义HTTP客户端配置,强制开启连接存活检测,避免复用失效连接:
import { MinioModule } from 'nestjs-minio-client'; import * as https from 'https'; // 需要导入https模块 @Module({ imports: [ MinioModule.register({ endPoint: minioConstants.MINIO_ENDPOINT, useSSL: true, accessKey: minioConstants.MINIO_ACCESSKEY, secretKey: minioConstants.MINIO_SECRETKEY, // 添加自定义HTTP客户端配置 httpClient: { keepAlive: true, timeout: 300000, // 5分钟超时,和Nginx配置对齐 agent: new https.Agent({ keepAlive: true, maxSockets: 50, // 根据你的业务量调整连接池大小 rejectUnauthorized: false, // 如果用的是自签SSL证书,需要开启这个 }) } }) ], controllers: [...], providers: [...], exports: [...] })
3. 给上传/删除操作添加重试机制
在UploadService里对MinIO操作添加重试逻辑,当遇到socket hang up这类连接错误时,自动重试,提升稳定性:
import { Injectable, Logger, HttpException, HttpStatus } from '@nestjs/common'; import { MinioService } from 'nestjs-minio-client'; import * as crypto from 'crypto' import { IMulterFile } from '@shared/interfaces/file.interface'; @Injectable() export class UploadService { private readonly baseBucket = 'users' private readonly logger = new Logger(UploadService.name); private readonly maxRetries = 3; // 最多重试3次 public get client() { return this.minio.client; } constructor(private readonly minio: MinioService) {} public async uploadImage(file: IMulterFile, baseBucket: string = this.baseBucket) { if(!(file.mimetype.includes('image/jpeg') || file.mimetype.includes('image/png'))) { throw new HttpException('仅支持JPG/PNG格式图片', HttpStatus.BAD_REQUEST) } // 生成文件名逻辑保持不变 let temp_filename = Date.now().toString() let hashedFileName = crypto.createHash('md5').update(temp_filename).digest("hex"); let ext = file.originalname.substring(file.originalname.lastIndexOf('.'), file.originalname.length); const metaData = { 'Content-Type': file.mimetype, 'X-Amz-Meta-Testing': 1234, }; const fileName = `${hashedFileName}${ext}`; const fileBuffer = file.buffer; // 重试逻辑 for (let retryCount = 0; retryCount < this.maxRetries; retryCount++) { try { await this.client.putObject(baseBucket, fileName, fileBuffer, metaData); return {filename: fileName}; } catch (error) { this.logger.error(`上传失败(第${retryCount+1}/${this.maxRetries}次重试): ${error.message}`); // 只有是连接类错误且还没到最大重试次数时才重试 if (error.message.includes('socket hang up') && retryCount < this.maxRetries - 1) { await new Promise(resolve => setTimeout(resolve, 1000)); // 重试前延迟1秒 continue; } throw new HttpException('文件上传失败', HttpStatus.INTERNAL_SERVER_ERROR); } } } async delete(objectName: string, baseBucket: string = this.baseBucket) { for (let retryCount = 0; retryCount < this.maxRetries; retryCount++) { try { await this.client.removeObject(baseBucket, objectName); return; } catch (error) { this.logger.error(`删除失败(第${retryCount+1}/${this.maxRetries}次重试): ${error.message}`); if (error.message.includes('socket hang up') && retryCount < this.maxRetries - 1) { await new Promise(resolve => setTimeout(resolve, 1000)); continue; } throw new HttpException('文件删除失败', HttpStatus.INTERNAL_SERVER_ERROR); } } } }
4. 调整MinIO服务器的空闲连接超时
启动MinIO容器时,添加--http-idle-timeout参数,延长MinIO服务器端的空闲连接超时时间,和前面的配置保持一致:
docker run -p 9000:9000 minio/minio server ./data --http-idle-timeout 300s
验证步骤
- 应用所有配置后,重启Nginx、MinIO容器和你的NestJS应用。
- 持续进行上传/删除测试,观察是否还会出现
socket hang up错误。 - 查看Nginx错误日志(
/var/log/nginx/error.log)和MinIO容器日志,确认连接断开的情况是否减少。
内容的提问来源于stack exchange,提问作者Ana Lava
相关产品推荐
相关产品推荐

