# 图片上传改造实施完成说明 **实施日期**:2025年1月 **改造状态**:✅ **已完成** --- ## 一、改造完成内容 ### 1.1 接口备份 ✅ 已创建以下备份方法: 1. **`Uploader_bak`** - 标准文件上传备份 - 接口路径:`POST /api/File/Uploader_bak/{type}` - 位置:`FileService.cs` 2. **`UploadBase64Image_bak`** - Base64图片上传备份 - 接口路径:`POST /api/File/UploadBase64Image_bak` - 位置:`FileService.cs` 3. **`UploadFileByType_bak`** - 核心上传逻辑备份 - 位置:`FileService.cs` --- ### 1.2 配置项添加 ✅ **配置文件**:`appsettings.json` **新增配置项**: ```json "NCC_App": { "LocalFileBaseUrl": "https://erp.lvqianmeiye.com" } ``` **配置说明**: - 用于返回本地文件的完整访问地址 - 生产环境:`https://erp.lvqianmeiye.com` - 开发环境:可配置为 `http://localhost:2011` 或其他地址 --- ### 1.3 KeyVariable 扩展 ✅ **文件**:`KeyVariable.cs` **新增属性**: ```csharp /// /// 本地文件访问基础URL(用于返回本地文件的完整访问地址) /// public static string LocalFileBaseUrl { get { var url = App.Configuration["NCC_App:LocalFileBaseUrl"] ?? App.Configuration["NCC_APP:LocalFileBaseUrl"] ?? App.Configuration["NCC_App:Domain"]; return string.IsNullOrEmpty(url) ? "http://localhost:2011" : url.TrimEnd('/'); } } ``` --- ### 1.4 核心方法改造 ✅ #### 1.4.1 Uploader 方法 **改造内容**: - ✅ 先上传到服务器本地 - ✅ 从服务器本地上传到OSS - ✅ OSS上传成功 → 删除本地文件 - ✅ OSS上传失败 → 保留本地文件 - ✅ 返回完整URL(OSS成功用OSS URL,失败用本地完整URL) **关键代码**: ```csharp // 先上传到本地,再上传到OSS var (ossSuccess, localPath, ossPath) = await UploadFileToLocalThenOSS( file, _filePath, // 本地存储路径 ossFilePath, // OSS存储路径 _fileName, forceStoreType); // 根据OSS上传结果返回URL if (type == "annexpic" && forceStoreType == "aliyun-oss") { if (ossSuccess) { fileUrl = await GetOSSAccessUrl(ossFilePath, _fileName); } else { // OSS上传失败,返回本地文件完整URL(降级方案) fileUrl = GetLocalFileUrl(type, _fileName); } } ``` --- #### 1.4.2 UploadBase64Image 方法 **改造内容**: - ✅ 先保存Base64数据到服务器本地 - ✅ 从服务器本地上传到OSS - ✅ OSS上传成功 → 删除本地文件 - ✅ OSS上传失败 → 保留本地文件 - ✅ 返回完整URL(OSS成功用OSS URL,失败用本地完整URL) **关键代码**: ```csharp // 先保存到本地,再上传到OSS var (ossSuccess, localPath, ossPath) = await UploadBase64ToLocalThenOSS( imageData, localFilePath, // 本地存储路径 ossFilePath, // OSS存储路径 fileName); // 根据OSS上传结果返回URL if (ossSuccess) { accessUrl = await GetOSSAccessUrl(ossFilePath, fileName); } else { // OSS上传失败,返回本地文件完整URL(降级方案) accessUrl = GetLocalFileUrl(imageType, fileName); } ``` --- ### 1.5 新增辅助方法 ✅ #### 1.5.1 GetLocalFileUrl 方法 **功能**:获取本地文件的完整访问URL **代码**: ```csharp [NonAction] private string GetLocalFileUrl(string type, string fileName) { var baseUrl = KeyVariable.LocalFileBaseUrl; var relativePath = string.Format("/api/File/Image/{0}/{1}", type, fileName); return $"{baseUrl}{relativePath}"; } ``` **返回示例**: - 生产环境:`https://erp.lvqianmeiye.com/api/File/Image/annexpic/20250123_123.jpg` - 开发环境:`http://localhost:2011/api/File/Image/annexpic/20250123_123.jpg` --- #### 1.5.2 UploadFileToLocalThenOSS 方法 **功能**:先上传到本地,再上传到OSS(标准文件上传) **流程**: 1. 保存文件到本地 2. 判断是否需要上传到OSS 3. 如果需要,从本地上传到OSS 4. OSS上传成功 → 删除本地文件 5. OSS上传失败 → 保留本地文件 **返回值**: - `OssSuccess`:OSS是否上传成功 - `LocalPath`:本地文件完整路径 - `OssPath`:OSS文件路径 --- #### 1.5.3 UploadBase64ToLocalThenOSS 方法 **功能**:先保存Base64数据到本地,再上传到OSS **流程**: 1. 保存Base64数据到本地 2. 从本地上传到OSS 3. OSS上传成功 → 删除本地文件 4. OSS上传失败 → 保留本地文件 **返回值**: - `OssSuccess`:OSS是否上传成功 - `LocalPath`:本地文件完整路径 - `OssPath`:OSS文件路径 --- ## 二、改造后的流程 ### 2.1 标准文件上传流程 ``` 1. 验证文件类型 2. 生成文件路径和文件名 3. 【新增】先上传到服务器本地 4. 【新增】从服务器本地上传到OSS 5. 【新增】OSS上传成功 → 删除本地文件 6. 【新增】OSS上传失败 → 保留本地文件 7. 根据OSS上传结果返回URL: - OSS成功:返回OSS访问URL(带签名) - OSS失败:返回本地文件完整URL(https://erp.lvqianmeiye.com/api/File/Image/...) 8. 返回结果 ``` --- ### 2.2 Base64图片上传流程 ``` 1. 解析Base64数据 2. 验证图片格式 3. 生成文件路径和文件名 4. 【新增】先保存Base64数据到服务器本地 5. 【新增】从服务器本地上传到OSS 6. 【新增】OSS上传成功 → 删除本地文件 7. 【新增】OSS上传失败 → 保留本地文件 8. 根据OSS上传结果返回URL: - OSS成功:返回OSS访问URL(带签名) - OSS失败:返回本地文件完整URL(https://erp.lvqianmeiye.com/api/File/Image/...) 9. 返回结果 ``` --- ## 三、配置说明 ### 3.1 配置文件位置 **文件**:`netcore/src/Application/NCC.API/appsettings.json` ### 3.2 配置项 ```json { "NCC_App": { "LocalFileBaseUrl": "https://erp.lvqianmeiye.com" } } ``` ### 3.3 环境配置 **生产环境**: ```json "LocalFileBaseUrl": "https://erp.lvqianmeiye.com" ``` **开发环境**: ```json "LocalFileBaseUrl": "http://localhost:2011" ``` **测试环境**: ```json "LocalFileBaseUrl": "http://erp_test.lvqianmeiye.com" ``` --- ## 四、URL返回规则 ### 4.1 OSS上传成功 **返回URL格式**: ``` https://lvqian-erip.oss-cn-chengdu.aliyuncs.com/2025/01/23/20250123_123.jpg?签名参数 ``` **特点**: - 带签名的临时访问URL(有效期24小时) - 如果配置了自定义域名,使用自定义域名 --- ### 4.2 OSS上传失败(降级方案) **返回URL格式**: ``` https://erp.lvqianmeiye.com/api/File/Image/annexpic/20250123_123.jpg ``` **特点**: - 完整的HTTP/HTTPS URL - 通过 `GetImg` 方法提供访问 - 本地文件保留,确保可以访问 --- ## 五、异常处理 ### 5.1 本地保存失败 **处理方式**:直接抛出异常,不进行OSS上传 **异常信息**: ``` 文件保存到本地失败: {错误信息} ``` --- ### 5.2 OSS上传失败 **处理方式**: - 捕获异常,不抛出 - 保留本地文件 - 返回本地文件完整URL(降级方案) **日志记录**(可选): ```csharp // 可以在这里添加日志记录: // _logger?.LogError(ex, $"文件上传到OSS失败,保留本地文件: {localFullPath}"); ``` --- ### 5.3 OSS上传成功但删除本地文件失败 **处理方式**: - 捕获异常,不抛出 - 不影响返回结果 - 返回OSS访问URL **日志记录**(可选): ```csharp // 可以在这里添加日志记录: // _logger?.LogWarning(ex, $"OSS上传成功但删除本地文件失败: {localFullPath}"); ``` --- ## 六、测试建议 ### 6.1 正常流程测试 1. **OSS上传成功**: - ✅ 文件保存到本地 - ✅ 文件上传到OSS - ✅ 本地文件被删除 - ✅ 返回OSS URL 2. **非OSS类型**: - ✅ 文件保存到本地 - ✅ 不进行OSS上传 - ✅ 返回本地完整URL --- ### 6.2 异常流程测试 1. **OSS上传失败**(模拟OSS服务不可用): - ✅ 文件保存到本地 - ✅ OSS上传失败 - ✅ 本地文件保留 - ✅ 返回本地完整URL(`https://erp.lvqianmeiye.com/api/File/Image/...`) 2. **本地保存失败**(模拟磁盘满): - ✅ 本地保存失败 - ✅ 抛出异常 - ✅ 不进行OSS上传 --- ### 6.3 URL验证测试 **OSS成功时**: - 验证返回的URL是OSS地址 - 验证URL可以正常访问 **OSS失败时**: - 验证返回的URL是本地完整URL - 验证URL格式:`https://erp.lvqianmeiye.com/api/File/Image/...` - 验证URL可以正常访问(通过 `GetImg` 方法) --- ## 七、文件清单 ### 7.1 修改的文件 1. **`FileService.cs`** - 改造 `Uploader` 方法 - 改造 `UploadBase64Image` 方法 - 新增 `GetLocalFileUrl` 方法 - 新增 `UploadFileToLocalThenOSS` 方法 - 新增 `UploadBase64ToLocalThenOSS` 方法 - 备份方法:`Uploader_bak`、`UploadBase64Image_bak`、`UploadFileByType_bak` 2. **`KeyVariable.cs`** - 新增 `LocalFileBaseUrl` 属性 3. **`appsettings.json`** - 新增 `LocalFileBaseUrl` 配置项 --- ## 八、注意事项 ### 8.1 配置检查 ✅ **必须配置** `LocalFileBaseUrl`: - 生产环境:`https://erp.lvqianmeiye.com` - 开发环境:`http://localhost:2011` - 测试环境:`http://erp_test.lvqianmeiye.com` --- ### 8.2 本地存储空间 ⚠️ **需要监控**: - 本地磁盘空间 - OSS上传失败后保留的本地文件数量 - 建议定期清理OSS上传失败后保留的本地文件 --- ### 8.3 文件权限 ✅ **确保**: - 应用有本地文件写入权限 - 应用有本地文件删除权限 - 应用有本地文件读取权限(用于上传到OSS) --- ### 8.4 路径安全 ✅ **已处理**: - 使用 `Path.Combine` 组合本地路径(防止路径遍历) - 使用正斜杠 `/` 组合OSS路径 --- ## 九、回滚方案 ### 9.1 如果改造后出现问题 **回滚步骤**: 1. 将 `Uploader` 方法内容替换为 `Uploader_bak` 的内容 2. 将 `UploadBase64Image` 方法内容替换为 `UploadBase64Image_bak` 的内容 3. 将 `UploadFileByType` 方法内容替换为 `UploadFileByType_bak` 的内容 **备份方法位置**: - `Uploader_bak`:`FileService.cs` - `UploadBase64Image_bak`:`FileService.cs` - `UploadFileByType_bak`:`FileService.cs` --- ## 十、后续优化建议 ### 10.1 日志记录 建议添加日志记录: - OSS上传成功/失败日志 - 本地文件删除成功/失败日志 - 便于问题排查和监控 ### 10.2 清理机制 建议实现定期清理机制: - 定期清理OSS上传失败后保留的本地文件 - 可以设置保留时间(如:7天后自动删除) ### 10.3 监控告警 建议添加监控: - 监控本地存储空间使用率 - 监控OSS上传失败率 - 监控本地文件数量 --- ## 十一、总结 ### 11.1 改造完成 ✅ **所有改造已完成**: - 接口备份 ✅ - 配置项添加 ✅ - 核心方法改造 ✅ - 辅助方法创建 ✅ - 异常处理完善 ✅ ### 11.2 改造效果 - ✅ 数据安全:本地有备份,OSS失败也能提供服务 - ✅ 降级方案:OSS不可用时自动降级到本地存储 - ✅ 完整URL:本地文件返回完整URL,便于前端使用 - ✅ 可配置:本地URL可通过配置文件设置 --- **改造完成时间**:2025年1月 **改造状态**:✅ **已完成,等待测试验证**