.NET Core 6 API:扩展名未知时如何读取(GET)文件
问题解决与代码优化建议
一、让GET方法支持任意上传文件类型的方案
当前GET方法硬编码了.pdf后缀,要实现支持所有上传类型的文件下载,核心是找到对应requestId+lineNumber的文件实际扩展名,再动态读取文件并设置正确的Content-Type。
实现思路
- 生成文件基础名称(
requestId与lineNumber拼接) - 遍历支持的扩展名,检查哪个文件实际存在
- 找到目标文件后,根据扩展名匹配对应MIME类型,返回文件流
修改后的Download方法
[HttpGet("Download/{requestId}/{lineNumber}")] public IActionResult Download([FromRoute] long requestId, [FromRoute] int lineNumber) { string baseFileName = requestId.ToString() + lineNumber.ToString(); string fileDownloadName = baseFileName + DateTime.Now.ToString("ddMMyyyy"); string filePathBase = Path.Combine(GetFilePath(), baseFileName); var supportedExts = new[] { "pdf", "doc", "docx" }; try { // 遍历支持的扩展名,查找实际存在的文件 foreach (var ext in supportedExts) { string fullPath = $"{filePathBase}.{ext}"; if (System.IO.File.Exists(fullPath)) { // 根据扩展名匹配对应的MIME类型 string contentType = ext switch { "pdf" => "application/pdf", "doc" => "application/msword", "docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document", _ => "application/octet-stream" }; var stream = new FileStream(fullPath, FileMode.Open); return File(stream, contentType, $"{fileDownloadName}.{ext}"); } } // 未找到对应文件时返回NotFound return NotFound("指定文件不存在"); } catch (Exception ex) { // 服务器内部错误返回500状态码,避免泄露敏感信息 return StatusCode(StatusCodes.Status500InternalServerError, "文件下载失败"); } }
二、Upload与Download方法的优化反馈
Upload方法优化点
- 路径拼接更安全:替换字符串拼接为
Path.Combine,自动适配不同操作系统的路径分隔符 - 扩展名处理更严谨:先判断扩展名是否为空,再统一转为小写避免大小写问题,同时用
HashSet提升格式校验效率 - 参数校验更完善:补充
formFile为空的检查,避免空引用异常 - 异常处理更合理:生产环境下不返回原始异常信息,改为通用错误提示,同时建议添加日志记录
- 返回结果更规范:返回结构化对象,方便前端解析
修改后的Upload方法:
[HttpPost("Upload/{requestId}/{lineNumber}")] public async Task<IActionResult> OnPostUploadAsync(IFormFile formFile, [FromRoute] long requestId, [FromRoute] int lineNumber) { // 检查文件是否为空或无内容 if (formFile == null || formFile.Length == 0) { return BadRequest("请选择有效的文件进行上传"); } try { string docId = requestId.ToString() + lineNumber.ToString(); string filepath = GetFilePath(); var supportedTypes = new HashSet<string> { "doc", "docx", "pdf" }; // 安全获取并处理文件扩展名 string fileExt = Path.GetExtension(formFile.FileName).TrimStart('.').ToLowerInvariant(); if (string.IsNullOrEmpty(fileExt) || !supportedTypes.Contains(fileExt)) { return BadRequest("文件格式无效,仅支持DOC、DOCX、PDF格式"); } // 拼接完整文件路径,自动创建目录(已存在则无操作) string concessionDocumentPath = Path.Combine(filepath, $"{docId}.{fileExt}"); Directory.CreateDirectory(filepath); // 覆盖已存在的文件 using (var stream = System.IO.File.Create(concessionDocumentPath)) { await formFile.CopyToAsync(stream); } return Ok(new { Message = $"文件 {formFile.FileName} 上传成功", FileId = docId }); } catch (Exception ex) { // 此处建议添加日志记录ex信息,方便排查问题 return StatusCode(StatusCodes.Status500InternalServerError, "文件上传失败,请稍后重试"); } }
Download方法原有问题优化
- 移除硬编码的
.pdf后缀,改为动态匹配实际文件 - 替换不安全的路径拼接方式,使用
Path.Combine保证跨平台兼容性 - 修正异常状态码:文件不存在返回
NotFound,服务器错误返回500,符合HTTP规范 - 动态设置MIME类型,确保浏览器能正确识别并处理不同格式的文件
三、通用优化建议
- 添加日志:在异常分支中注入
ILogger记录详细错误信息,便于后续排查问题 - 文件大小限制:在Upload方法中添加文件大小校验,防止上传过大文件占用服务器资源
- 权限控制:如果接口需要权限访问,添加
[Authorize]属性实现身份验证与授权 - 依赖注入规范:确保
_environment通过构造函数注入,符合ASP.NET Core依赖注入设计原则
内容的提问来源于stack exchange,提问作者SmithsonG
相关产品推荐
相关产品推荐

