using AgriculturalPlatform.Api.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace AgriculturalPlatform.Api.Controllers; /// /// 附件读取代理:OSS 模式(私有桶)下前端通过 /api/files/{key} 访问图片, /// 后端实时从 OSS 拉取并回传,避免将 Bucket 设为公共读而泄露身份证等敏感信息。 /// 本地存储模式不经过此接口(前端直接走静态文件 /uploads)。 /// [ApiController] [Route("api/files")] [AllowAnonymous] public class FilesController(IFileStorage storage) : ControllerBase { /// /// 读取附件。key 形如 uploads/avatar/202608/xxx.png(必须限定 uploads/ 前缀,防止越权读取)。 /// 通过 FileStreamResult 边读边传,减少大图内存占用。 /// [HttpGet("{**key}")] [ResponseCache(Duration = 300)] // 5 分钟缓存,减少重复拉取 public async Task Get(string key) { if (string.IsNullOrWhiteSpace(key) || !key.StartsWith("uploads/")) return BadRequest(new { message = "无效的文件路径" }); var file = await storage.OpenReadAsync(key); if (file is null) return NotFound(new { message = "文件不存在或已被删除" }); var (stream, contentType) = file.Value; return File(stream, contentType, enableRangeProcessing: true); } }