Minio 模拟S3云存储

目录

一、前言

二、官网下载

[三、启动 minio 服务端](#三、启动 minio 服务端)

1.启动服务端

2.使用服务端

3.公开访问某桶文件

四、C#项目使用minio上传文件

1.安装Minio包

[2.在 C# 项目里引用](# 项目里引用)

[3.C# 项目配置 MinIO 服务端](# 项目配置 MinIO 服务端)

4.初始化前端页面

(1)后端跳转到前端页面

(2)前端页面

5.controller.cs上传文件

6.结合DI注册(可跳过)

(1)在appsettings.json中补充

[(2)新建 LyWeb\Data\MinioHelper.cs](#(2)新建 LyWeb\Data\MinioHelper.cs)

(3)在programs.cs中补充

(4)修改controller.cs

7.实现下载

(1)前端补充

(2)后端补充


一、前言

开源。类似于私人云存储(其实是存在本地,只是模拟云存储)。

用处:多个系统访问同一批文件;用户权限控制;大文件分片或并发上传;将来可直接换成S3云存储(即,将Minio换成S3时,代码几乎不用改)。

写这篇文章的主要目的:模拟S3云存储(实现上传存储、下载文件),因为minio兼容 Amazon S3接口,提供SDK支持,将来换成S3更方便。

二、官网下载

在官网 https://github.com/minio 中 下载minio和mc,在页面code下方一直滚动找到下载链接

(1)minio下载:https://dl.min.io/server/minio/release/

(2)mc下载:https://dl.min.io/client/mc/release/windows-amd64/mc.exe

(3)存放位置:自定义创建根目录,并在目录里创建bin、data、logs文件夹,将minio.exe和mc.exe放在bin文件夹里。

三、启动 minio 服务端

1.启动服务端

不要直接用exe,要用命名行。且在bin目录下打开cmd。

输入以下命令:

bash 复制代码
# 1.设置服务端登录用户
setx MINIO_ROOT_USER 用户名

# 2.设置密码
setx MINIO_ROOT_PASSWORD 密码

# 3.启动服务端(两种命令)
#(1)
.\\minio.exe server E:\\minio\\data --console-address "127.0.0.1:9001" --address "127.0.0.1:9000"

#(2)
.\\minio.exe server E:\\LayuiAdmin\\minio\\data --console-address ":9001" --address ":9000"

# 该行命令的意义分别代表 启动 MinIO 服务器、指定数据目录、指定控制台地址、指定服务地址。
# 其中,控制台访问 <http://127.0.0.1:9001>。S3 API 服务访问 <http://127.0.0.1:9000>。

图例:

注意:首次使用启动命令打开的登录页面,需用默认账密登录(第二次打开使用自定义的账密)

2.使用服务端

访问页面:http://127.0.0.1:9001

输入账密即可登录。

首次使用启动命令打开的登录页面,需用默认账密 minioadmin:minioadmin登录(下一次使用启动命令打开的登录页面,则用自定义的账密)。

3.公开访问某桶文件

若C#项目想访问桶文件却没权限,F12的Network中显示路由是403,则需在服务端开启访问权限

即,在minio.exe所在的bin目录下打开cmd,输入命令:

bash 复制代码
# 设置别名为local 方便后续操作(成功会显示:Added `local` successfully.)
mc alias set local <http://127.0.0.1:9000> admin admin2026

# 查看所有桶(会看到 0B bucket001/ )
mc ls local

# 设置可访问(成功会显示:Access permission for `local/bucket001` is set to `download`)
mc anonymous set download local/bucket001
# 其中,download 表示只允许匿名访问下载,不允许写入

# 恢复私有(撤销匿名访问)
mc anonymous set none local/bucket001

如图:

四、C#项目使用minio上传文件

1.安装Minio包

在 Visual Studio 的 NuGet 包管理器里搜索:Minio,并安装

安装成功后,在项目的.csproj文件中会自动生成:

cs 复制代码
<PackageReference Include="Minio" Version="7.0.0" />

2.在 C# 项目里引用

复制代码
using Minio;
using Minio.Exceptions;

3.C# 项目配置 MinIO 服务端

配置信息有:

S3 API 地址:http://127.0.0.1:9000

Access Key:登录用户名

Secret Key:登录密码

配置例子如下:

cs 复制代码
public class MinioController : Controller
{
   private readonly IMinioClient _minioClient; // 使用minio模拟上传文件到云端
   public MinioController()
   {
	   _minioClient = new MinioClient()
	   .WithEndpoint("127.0.0.1", 9000)       // S3 API地址 和 端口
	   .WithCredentials("admin", "admin2026") // 账号密码
	   .WithSSL(false)   // 是否 https
	   .Build();
   }
}

4.初始化前端页面

(1)后端跳转到前端页面
cs 复制代码
[HttpGet]
public IActionResult Minio()
{
	return View("~/Views/MinioFile/Minio.cshtml");
}
(2)前端页面
cpp 复制代码
@{
    ViewData["Title"] = "上传云端";
}

<div class="min-vh-100 d-flex justify-content-center align-items-center">
    <div class="card">
        <button type="button" class="layui-btn" id="uploadBtn">上传文件</button>
        <img id="avatarImg" src="" style="width:150px;height:150px;border:none;" />
    </div>
</div>

@section Scripts {
    <partial name="_ValidationScriptsPartial" /> <!--配合 div asp-validation-summary-->
    <script>
        layui.use(['upload', 'layer'], function () {
            var upload = layui.upload;
            var layer = layui.layer;

            upload.render({
                elem: '#uploadBtn',
                url: '/Minio/Upload',
                accept: 'file',
                choose: function(obj){
                    console.log("已选中文件");
                },
                done: function (res) {
                    if (res.res) {
                        layer.msg("上传成功");
                        document.getElementById("avatarImg").src = res.data;
                    } else {
                        layer.msg("上传失败:" + res.msg);
                    }
                }
            });
        });
    </script>

}

5.controller.cs上传文件

cs 复制代码
using Microsoft.AspNetCore.Mvc;
using Minio;
using Minio.DataModel.Args;


namespace LyWeb.Controllers
{
	public class MinioHelper
	{
		public string Endpoint { get; set; }
		public int Port { get; set; }
		public string AccessKey { get; set; }
		public string SecretKey { get; set; }
		public bool UseSSL { get; set; }
	}


	public class MinioController : Controller
	{
		private readonly IMinioClient _minioClient; // 使用minio模拟上传文件到云端

		public MinioController()
		{
			_minioClient = new MinioClient()
			.WithEndpoint("127.0.0.1", 9000)       // S3 API地址 和 端口
			.WithCredentials("admin", "admin2026") // 账号密码
			.WithSSL(false)   // 是否 https
			.Build();
		}

		public IActionResult Index()
		{
			return View();
		}

		[HttpGet]
		public IActionResult Minio()
		{
			return View("~/Views/Account/Minio.cshtml");
		}

		[HttpPost]
		public async Task<IActionResult> Upload(IFormFile file)
		{
			// 检查文件是否为空
			if (file == null || file.Length == 0)
			{
				return Ok(new { res = false, msg = "请选择文件" });
			}

			try
			{
				// 1.1 配置桶名 
				var bucketName = "bucket001";

				// 1.2 创建桶名(若存在,则直接跳过创建)
				bool bk = await _minioClient.BucketExistsAsync( new BucketExistsArgs().WithBucket(bucketName) );
				if (!bk)
				{
					await _minioClient.MakeBucketAsync( new MakeBucketArgs().WithBucket(bucketName) );
				}

				// 2. 生成唯一文件名(防重复)
				var fileExt = Path.GetExtension(file.FileName); // 获取文件名后缀(如.png)
				var objectName = Guid.NewGuid().ToString() + fileExt; // 生成唯一值(如 DBKFGFG01bdjksf.png)

				// 3. 上传
				using (var stream = file.OpenReadStream())
				{
					await _minioClient.PutObjectAsync(
						new PutObjectArgs()
							.WithBucket(bucketName)
							.WithObject(objectName)
							.WithStreamData(stream)
							.WithObjectSize(file.Length)
							.WithContentType(file.ContentType)
					);
				}

				// 4. 返回访问地址
				var url = $"http://127.0.0.1:9000/{bucketName}/{objectName}";

				return Ok(new { res = true, data= url });
			}
			catch (Minio.Exceptions.ConnectionException ex)
			{
				return Ok(new { res = false, msg = $"无法连接到 MinIO 服务" });
			}
			catch (Minio.Exceptions.AccessDeniedException ex)
			{
				return Ok(new { res = false, msg = $"MinIO 认证失败" });
			}
			catch (Exception ex)
			{
				return Ok(new { res = false, msg = $"Minio服务 连接失败 / DNS错误 / 认证失败: {ex.Message}" });
			}
		}

	}
}

6.结合DI注册(可跳过)

前面的内容已经可以实现模拟S3文件上传,若想统一设置minio服务的配置,则可接着改

(1)在appsettings.json中补充
javascript 复制代码
  "Minio": {
    "Endpoint": "127.0.0.1", // 设置 minio 端口
    "Port": 9000, // 设置 minio API地址
    "AccessKey": "admin", // 设置账号
    "SecretKey": "admin2026", // 设置密码
    "UseSSL": false // 是否使用 https
  },
(2)新建 LyWeb\Data\MinioHelper.cs
javascript 复制代码
namespace LyWeb.Data
{
	public class MinioHelper
	{
		public string Endpoint { get; set; }
		public int Port { get; set; }
		public string AccessKey { get; set; }
		public string SecretKey { get; set; }
		public bool UseSSL { get; set; }
	}

}
(3)在programs.cs中补充
javascript 复制代码
using LyWeb.LyData;
using Microsoft.Extensions.Options;
using Minio;

#region 注册Minio
// 绑定配置(把 appsettings.json Minio 节点绑定到 MinioHelper 强类型类,方便获取配置)
builder.Services.Configure<MinioHelper>(
	builder.Configuration.GetSection("Minio")
);
// 注册 MinioClient
builder.Services.AddSingleton<IMinioClient>(sp =>
{
	// 前面builder.Services.Configure<MinioHelper>注册到依赖注入容器,即可通过 IOptions<MinioHelper> 随时获取配置值
	var options = sp.GetRequiredService<IOptions<MinioHelper>>().Value; 
	return new MinioClient()
		.WithEndpoint(options.Endpoint, options.Port) // 设置 API地址 和 端口
		.WithCredentials(options.AccessKey, options.SecretKey) // 设置账号密码
		.WithSSL(options.UseSSL) // 是否使用 https
		.Build(); // 构建客户端对象
});
#endregion
(4)修改controller.cs
cs 复制代码
//todo-ly:0319
using LyWeb.Data;
using Microsoft.AspNetCore.Mvc;
using Minio;
using Minio.DataModel.Args;
using Microsoft.Extensions.Options;


namespace LyWeb.Controllers
{

	public class MinioController : Controller
	{
		private readonly IMinioClient _minioClient; // 使用minio模拟上传文件到云端
		private readonly MinioHelper _minioConfig; // 获取minio配置项的值

		public MinioController(IMinioClient minioClient, IOptions<MinioHelper> optMinio)
		{
			_minioClient = minioClient;
			_minioConfig = optMinio.Value;
		}

		public IActionResult Index()
		{
			return View();
		}

		[HttpGet]
		public IActionResult Minio()
		{
			return View("~/Views/Account/Minio.cshtml");
		}

		[HttpPost]
		public async Task<IActionResult> Upload(IFormFile file)
		{
			// 检查文件是否为空
			if (file == null || file.Length == 0)
			{
				return Ok(new { res = false, msg = "请选择文件" });
			}

			try
			{
				// 1.1 配置桶名 
				var bucketName = "bucket001";

				// 1.2 创建桶名(若存在,则直接跳过创建)
				bool bk = await _minioClient.BucketExistsAsync( new BucketExistsArgs().WithBucket(bucketName) );
				if (!bk)
				{
					await _minioClient.MakeBucketAsync( new MakeBucketArgs().WithBucket(bucketName) );
				}

				// 2. 生成唯一文件名(防重复)
				var fileExt = Path.GetExtension(file.FileName); // 获取文件名后缀(如.png)
				var objectName = Guid.NewGuid().ToString() + fileExt; // 生成唯一值(如 DBKFGFG01bdjksf.png)

				// 3. 上传
				using (var stream = file.OpenReadStream())
				{
					await _minioClient.PutObjectAsync(
						new PutObjectArgs()
							.WithBucket(bucketName)
							.WithObject(objectName)
							.WithStreamData(stream)
							.WithObjectSize(file.Length)
							.WithContentType(file.ContentType)
					);
				}

				// 4. 返回访问地址
				var url = $"{(_minioConfig.UseSSL ? "https" : "http")}://{_minioConfig.Endpoint}:{_minioConfig.Port}/{bucketName}/{objectName}";

				return Ok(new { res = true, data= url });
			}
			catch (Minio.Exceptions.ConnectionException ex)
			{
				return Ok(new { res = false, msg = $"无法连接到 MinIO 服务" });
			}
			catch (Minio.Exceptions.AccessDeniedException ex)
			{
				return Ok(new { res = false, msg = $"MinIO 认证失败" });
			}
			catch (Exception ex)
			{
				return Ok(new { res = false, msg = $"Minio服务 连接失败 / DNS错误 / 认证失败: {ex.Message}" });
			}
		}

	}
}

7.实现下载

(1)前端补充
html 复制代码
<button class="layui-btn" id="downloadBtn">下载</button>
<script>
layui.use(['upload', 'layer'], function () {
    var upload = layui.upload;
    var layer = layui.layer;

    document.getElementById("downloadBtn").addEventListener("click", function () {
       // 要下载的文件
       var downfile = encodeURIComponent("XXX.png");

       // 先请求检查接口
       fetch(`/Minio/CheckFile?objectName=${downfile}`)
       .then(res => res.json())
       .then(res => {
           if (!res.res) {
               layer.msg("文件不存在或未上传");
               return;
           }
           // 再触发下载
           window.location.href = `/Minio/DownLoad?objectName=${downfile}`;
           layer.msg("文件下载成功");
       });
    });
}
</script>
        
(2)后端补充
cs 复制代码
		[HttpGet]
		public async Task<IActionResult> CheckFile(string objectName)
		{
			var bucketName = "bucket001";

			// 检查是否文件存在
			try
			{
				await _minioClient.StatObjectAsync(
					new StatObjectArgs()
						.WithBucket(bucketName)
						.WithObject(objectName) // "XXX.png"
				);

				return Ok(new { res = true });
			}
			catch (Exception e)
			{
				return Ok(new { res = false, msg = $"Error occurred: {e.Message}" });
			}
		}

		[HttpGet]
		public async Task<IActionResult> DownLoad(string objectName)
		{
			var bucketName = "bucket001";

			try
			{
				var ms = new MemoryStream();

				// 获取文件
				await _minioClient.GetObjectAsync(
					new GetObjectArgs()
						.WithBucket(bucketName)
						.WithObject(objectName) // "XXX.png"
						.WithCallbackStream(stream =>
						{
							stream.CopyTo(ms);
						})
				);
				ms.Position = 0;

				// 返回文件给浏览器(让浏览器下载)
				return File(ms, "application/octet-stream", objectName);
			}
			catch (Exception e)
			{
				return Ok(new { res = false, msg = $"Error occurred: {e.Message}" });
			}
		}
相关推荐
bloglin999991 天前
python离线安装minio依赖异常
minio
分布式存储与RustFS3 天前
OpenClaw存储选型:RustFS vs MinIO,本地AI智能体谁更适配?
私有化部署·minio·本地ai·rustfs·openclaw·ai存储·国产开源
百里杨9 天前
ACPI电源按钮唤醒S3切换到S0流程(附流程图)
s3·acpi·s0
百里杨9 天前
ACPI休眠按钮触发S0切换到S3流程(附流程图)
s3·acpi·s0
vortex51 个月前
MinIO 与 mc 客户端完整使用指南
aws·minio·云技术
spencer_tseng1 个月前
Thumbnail display
java·minio
jfqqqqq1 个月前
minIO分页请求maxKeys无效的问题
java·sdk·minio·分页
小吴先生6661 个月前
Minio存储默认桶类型private,无法修改桶类型public,导致图片外部无法访问
运维·服务器·minio·权限
分布式存储与RustFS1 个月前
从MinIO到RustFS:一次关于性能、安全与开源协议的实战迁移
开发语言·安全·rust·开源协议·minio·企业存储·rustfs