AspNetCore基于静态文件中间件实现的图床

基于 ASP.NET Core 静态文件中间件实现的高性能图床系统

先说一下我为什么做这个图床,我之前一直是使用的 picgo 的图床,直到后面有一天我突然发现这个图床的图片全丢,然后担心换图床后再次出现这样的情况,恰好自己有云服务器,所以就自己搭建了一个图床。本文将分享一个基于 ASP.NET Core Minimal API + 静态文件中间件实现的轻量级图床方案,同时分享一下部署时自己踩过的坑。


克隆仓库

1
git clone https://github.com/lxy1234cn/AspNetCoreFileHosting.git

使用效果:

屏幕截图 2026-04-03 110401


在线使用地址:

https://file.filepunk.top/filehosting.html

设计思路

这个图床的核心理念是:

用文件系统代替数据库,用静态文件中间件代替文件服务接口

可能会需要手动创建 uploads 文件夹,同时要在 uploads 的 属性 —> 安全 中,设置IIS用户的权限

屏幕截图 2026-04-03 103227

核心架构:

1
2
3
4
5
客户端 → 上传接口 → 文件系统 (uploads)

静态文件中间件

/files/xxx 直接访问

核心技术点

静态文件映射

1
2
3
4
5
6
7
8
9
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(uploadsPath),
RequestPath = "/files",
OnPrepareResponse = ctx =>
{
ctx.Context.Response.Headers.Append("Cache-Control", "public, max-age=3600");
}
});

作用:

  • /files/xxx.jpg → 直接访问服务器文件
  • 浏览器缓存 1 小时(减少带宽)

大文件上传优化(重点)

传统方式:

1
上传 → 临时文件 → 再写入目标目录

该方案:

1
2
上传 → 直接流式写入 uploads,不经过 temp 文件夹
这是重点,避免了大文件上传时的性能问题和磁盘空间占用。

之所以选择这个方案,是因为,在 IIS 中默认设置中,如果传输的文件小于 10MB ,在上传时会存入临时文件夹,超过了10MB,就会被终止,所以直接流式写入

1
2
3
4
await using (var fileStream = File.Create(filePath))
{
await section.Body.CopyToAsync(fileStream);
}
  • 不占用 temp 目录
  • 不爆内存

文件类型白名单

安全配置

1
2
3
4
5
6
7
8
9
// 允许的文件类型
.jpg .jpeg .png .gif .webp .bmp .svg // 图片
.pdf .txt .doc .docx .xls .xlsx // 文档
.zip .rar .7z // 压缩包
.mp3 .mp4 .wav // 音视频

// 上传限制
单文件最大: 100MB
请求体限制: 100MB
1
2
3
4
var allowedExtensions = new HashSet<string>
{
".jpg", ".png", ".webp", ...
};

防止:

  • 上传脚本文件(.exe / .js)
  • 安全风险

多格式链接生成(图床核心)

1
2
3
4
5
6
formats = {
raw: 原始链接
markdown: ![]()
html: <img>
htmlSmall / Medium / Large
}

举例:

1
![image](https://xxx/files/a.png)
1
<img src="https://xxx/files/a.png" width="300" />

分页查询(避免炸接口)

1
2
.Skip((page - 1) * pageSize)
.Take(pageSize)

返回结构:

1
2
3
4
5
6
{
"files": [],
"total": 100,
"page": 1,
"totalPages": 9
}
  • 前端无限滚动
  • 控制接口压力

安全删除(防路径穿越)

1
2
3
var fullPath = Path.GetFullPath(filePath);
if (!fullPath.StartsWith(uploadsFullPath))
return Results.BadRequest("非法路径");

防止攻击:

1
/api/delete/../../windows/system32

文件统计接口

1
2
3
4
{
count: 文件数量,
totalSize: 总大小
}

API端点

端点 方法 说明
GET /api/hello - 服务健康检查
GET /api/stats - 文件统计(数量/总大小)
GET /api/list GET 分页列表 ?page=1&pageSize=12
POST /api/upload POST 多文件上传(multipart/form-data)
DELETE /api/delete/{fileName} DELETE 删除指定文件
/files/{fileName} GET 静态文件访问(带缓存头)

生产部署

环境要求
部分网站会要求 HTTPS(部分网站图片显示必需),不会设置 SSL 的,去看我的其他文章里面有,如果要加 IP限流,我的文章里面也有

使用场景

图床服务 - 为 Markdown 文档、博客提供稳定图片外链
临时文件中转 - 团队内部文件快速共享
静态资源托管 - 小型项目的附件存储方案