Commit addd9f4c79a923291d29cbc30b30003d8d5b62d1
1 parent
33599f59
feat: 配置annexpic接口使用阿里云OSS存储
- 创建annexpic_bak备份接口 - 配置阿里云OSS存储(成都区域) - annexpic接口强制使用阿里云OSS,不受全局FileStoreType配置影响 - 修复OSS路径格式问题(使用正斜杠) - 更新BucketName为lvqian-erip
Showing
3 changed files
with
74 additions
and
13 deletions
netcore/src/Application/NCC.API.Core/Startup.cs
| @@ -106,6 +106,38 @@ namespace NCC.API.Core | @@ -106,6 +106,38 @@ namespace NCC.API.Core | ||
| 106 | 106 | ||
| 107 | #endregion | 107 | #endregion |
| 108 | 108 | ||
| 109 | + #region 阿里云OSS | ||
| 110 | + | ||
| 111 | + var aliyunOSSEndpoint = App.Configuration["NCC_App:AliyunOSS:Endpoint"]; | ||
| 112 | + var aliyunOSSAccessKey = App.Configuration["NCC_App:AliyunOSS:AccessKeyId"]; | ||
| 113 | + var aliyunOSSSecretKey = App.Configuration["NCC_App:AliyunOSS:AccessKeySecret"]; | ||
| 114 | + var aliyunOSSRegion = App.Configuration["NCC_App:AliyunOSS:Region"]; | ||
| 115 | + var bucketName = App.Configuration["NCC_App:BucketName"]; | ||
| 116 | + | ||
| 117 | + if (!string.IsNullOrEmpty(aliyunOSSEndpoint) && !string.IsNullOrEmpty(aliyunOSSAccessKey) && !string.IsNullOrEmpty(aliyunOSSSecretKey)) | ||
| 118 | + { | ||
| 119 | + services.AddOSSService("aliyun", option => | ||
| 120 | + { | ||
| 121 | + option.Provider = OSSProvider.Aliyun; | ||
| 122 | + // 阿里云OSS Endpoint格式:oss-{region}.aliyuncs.com | ||
| 123 | + // 注意:不要包含bucket名称,只需要区域Endpoint | ||
| 124 | + option.Endpoint = aliyunOSSEndpoint; | ||
| 125 | + option.AccessKey = aliyunOSSAccessKey; | ||
| 126 | + option.SecretKey = aliyunOSSSecretKey; | ||
| 127 | + option.IsEnableHttps = true; | ||
| 128 | + option.IsEnableCache = true; | ||
| 129 | + // 对于OnceMi.AspNetCore.OSS,Region是可选的 | ||
| 130 | + // 但如果出现Endpoint不匹配错误,可能需要明确设置Region | ||
| 131 | + // 成都区域的Region格式:cn-chengdu | ||
| 132 | + if (!string.IsNullOrEmpty(aliyunOSSRegion)) | ||
| 133 | + { | ||
| 134 | + option.Region = aliyunOSSRegion; | ||
| 135 | + } | ||
| 136 | + }); | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | + #endregion | ||
| 140 | + | ||
| 109 | #region 微信 | 141 | #region 微信 |
| 110 | services.AddSenparcGlobalServices(App.Configuration)//Senparc.CO2NET 全局注册 | 142 | services.AddSenparcGlobalServices(App.Configuration)//Senparc.CO2NET 全局注册 |
| 111 | .AddSenparcWeixinServices(App.Configuration);//Senparc.Weixin 注册(如果使用Senparc.Weixin SDK则添加) | 143 | .AddSenparcWeixinServices(App.Configuration);//Senparc.Weixin 注册(如果使用Senparc.Weixin SDK则添加) |
netcore/src/Application/NCC.API/appsettings.json
| @@ -33,7 +33,7 @@ | @@ -33,7 +33,7 @@ | ||
| 33 | "DBType": "MySql", //MySql;SqlServer;Oracle;PostgreSQL;Dm;Kdbndp; | 33 | "DBType": "MySql", //MySql;SqlServer;Oracle;PostgreSQL;Dm;Kdbndp; |
| 34 | //SqlServer | 34 | //SqlServer |
| 35 | // "DefaultConnection": "Data Source=localhost;Initial Catalog={0};User ID=sqladmin;Password=P@ssw0rd;MultipleActiveResultSets=true" | 35 | // "DefaultConnection": "Data Source=localhost;Initial Catalog={0};User ID=sqladmin;Password=P@ssw0rd;MultipleActiveResultSets=true" |
| 36 | - "DefaultConnection": "Database={0};Data Source=rm-bp19ohrgc6111ynzh1o.mysql.rds.aliyuncs.com;Port=3306;User Id=netteam;Password=netteam;Charset=utf8;TreatTinyAsBoolean=true;" | 36 | + "DefaultConnection": "Database={0};Data Source=rm-2vccze142rc9a8f58bo.mysql.cn-chengdu.rds.aliyuncs.com;Port=3306;User Id=lvqiansql;Password=LvQ1@n!20251211;Charset=utf8;TreatTinyAsBoolean=true;" |
| 37 | 37 | ||
| 38 | }, | 38 | }, |
| 39 | "SpecificationDocumentSettings": { | 39 | "SpecificationDocumentSettings": { |
| @@ -204,9 +204,16 @@ | @@ -204,9 +204,16 @@ | ||
| 204 | "domainKey": "yozoHbiPMzu50374" | 204 | "domainKey": "yozoHbiPMzu50374" |
| 205 | }, | 205 | }, |
| 206 | //Minio | 206 | //Minio |
| 207 | - "BucketName": "NCCsoftoss", | 207 | + "BucketName": "lvqian-erip", |
| 208 | //文件存储类型(本地:local,MinIo:minio,阿里云:aliyun-oss,腾讯云:tencent-cos) | 208 | //文件存储类型(本地:local,MinIo:minio,阿里云:aliyun-oss,腾讯云:tencent-cos) |
| 209 | "FileStoreType": "local", | 209 | "FileStoreType": "local", |
| 210 | + //阿里云OSS配置 | ||
| 211 | + "AliyunOSS": { | ||
| 212 | + "AccessKeyId": "LTAI5t6h4i95uapwzDwKfNxi", | ||
| 213 | + "AccessKeySecret": "84dpUAlu2eoyFOIEhFGkZlIy45h0B6", | ||
| 214 | + "Endpoint": "oss-cn-chengdu.aliyuncs.com", | ||
| 215 | + "Region": "cn-chengdu" | ||
| 216 | + }, | ||
| 210 | //================== 系统错误邮件报告反馈相关 ============================== --> | 217 | //================== 系统错误邮件报告反馈相关 ============================== --> |
| 211 | //软件的错误报告 | 218 | //软件的错误报告 |
| 212 | "ErrorReport": "false", | 219 | "ErrorReport": "false", |
netcore/src/Modularity/System/NCC.System/Service/Common/FileService.cs
| @@ -64,7 +64,11 @@ namespace NCC.System.Service.Common | @@ -64,7 +64,11 @@ namespace NCC.System.Service.Common | ||
| 64 | throw NCCException.Oh(ErrorCode.D1800); | 64 | throw NCCException.Oh(ErrorCode.D1800); |
| 65 | var _filePath = GetPathByType(type); | 65 | var _filePath = GetPathByType(type); |
| 66 | var _fileName = DateTime.Now.ToString("yyyyMMdd") + "_" + YitIdHelper.NextId().ToString() + Path.GetExtension(file.FileName); | 66 | var _fileName = DateTime.Now.ToString("yyyyMMdd") + "_" + YitIdHelper.NextId().ToString() + Path.GetExtension(file.FileName); |
| 67 | - await UploadFileByType(file, _filePath, _fileName); | 67 | + |
| 68 | + // annexpic 类型强制使用阿里云OSS存储 | ||
| 69 | + string forceStoreType = type == "annexpic" ? "aliyun-oss" : null; | ||
| 70 | + await UploadFileByType(file, _filePath, _fileName, forceStoreType); | ||
| 71 | + | ||
| 68 | return new { name = _fileName, url = string.Format("/api/File/Image/{0}/{1}", type, _fileName) }; | 72 | return new { name = _fileName, url = string.Format("/api/File/Image/{0}/{1}", type, _fileName) }; |
| 69 | } | 73 | } |
| 70 | 74 | ||
| @@ -79,7 +83,9 @@ namespace NCC.System.Service.Common | @@ -79,7 +83,9 @@ namespace NCC.System.Service.Common | ||
| 79 | public async Task<IActionResult> GetImg(string type, string fileName) | 83 | public async Task<IActionResult> GetImg(string type, string fileName) |
| 80 | { | 84 | { |
| 81 | var filePath = Path.Combine(GetPathByType(type), fileName.Replace("@", ".")); | 85 | var filePath = Path.Combine(GetPathByType(type), fileName.Replace("@", ".")); |
| 82 | - return await DownloadFileByType(filePath, fileName); | 86 | + // annexpic 类型强制使用阿里云OSS存储 |
| 87 | + string forceStoreType = type == "annexpic" ? "aliyun-oss" : null; | ||
| 88 | + return await DownloadFileByType(filePath, fileName, forceStoreType); | ||
| 83 | //return new FileStreamResult(new FileStream(filePath, FileMode.Open), "application/octet-stream") { FileDownloadName = fileName }; | 89 | //return new FileStreamResult(new FileStream(filePath, FileMode.Open), "application/octet-stream") { FileDownloadName = fileName }; |
| 84 | } | 90 | } |
| 85 | 91 | ||
| @@ -181,7 +187,9 @@ namespace NCC.System.Service.Common | @@ -181,7 +187,9 @@ namespace NCC.System.Service.Common | ||
| 181 | fileDownloadName = Path.GetFileName(filePath); | 187 | fileDownloadName = Path.GetFileName(filePath); |
| 182 | if (fileDownloadName.IsNullOrWhiteSpace()) | 188 | if (fileDownloadName.IsNullOrWhiteSpace()) |
| 183 | fileDownloadName = fileName.Replace(GetPathByType(type), ""); | 189 | fileDownloadName = fileName.Replace(GetPathByType(type), ""); |
| 184 | - return await DownloadFileByType(filePath, fileDownloadName); | 190 | + // annexpic 类型强制使用阿里云OSS存储 |
| 191 | + string forceStoreType = type == "annexpic" ? "aliyun-oss" : null; | ||
| 192 | + return await DownloadFileByType(filePath, fileDownloadName, forceStoreType); | ||
| 185 | } | 193 | } |
| 186 | else | 194 | else |
| 187 | { | 195 | { |
| @@ -198,15 +206,19 @@ namespace NCC.System.Service.Common | @@ -198,15 +206,19 @@ namespace NCC.System.Service.Common | ||
| 198 | /// <param name="file"></param> | 206 | /// <param name="file"></param> |
| 199 | /// <param name="filePath"></param> | 207 | /// <param name="filePath"></param> |
| 200 | /// <param name="fileName"></param> | 208 | /// <param name="fileName"></param> |
| 209 | + /// <param name="forceStoreType">强制使用指定的存储类型(如:aliyun-oss),如果为空则使用配置的存储类型</param> | ||
| 201 | /// <returns></returns> | 210 | /// <returns></returns> |
| 202 | [NonAction] | 211 | [NonAction] |
| 203 | - public async Task UploadFileByType(IFormFile file, string filePath, string fileName) | 212 | + public async Task UploadFileByType(IFormFile file, string filePath, string fileName, string forceStoreType = null) |
| 204 | { | 213 | { |
| 205 | try | 214 | try |
| 206 | { | 215 | { |
| 207 | var bucketName = KeyVariable.BucketName; | 216 | var bucketName = KeyVariable.BucketName; |
| 208 | - var fileStoreType = KeyVariable.FileStoreType; | ||
| 209 | - var uploadPath = Path.Combine(filePath, fileName); | 217 | + var fileStoreType = !string.IsNullOrEmpty(forceStoreType) ? forceStoreType : KeyVariable.FileStoreType; |
| 218 | + // OSS路径使用正斜杠,不使用Path.Combine | ||
| 219 | + var uploadPath = fileStoreType == "aliyun-oss" || fileStoreType == "tencent-cos" || fileStoreType == "minio" | ||
| 220 | + ? $"{filePath.TrimEnd('/').TrimEnd('\\')}/{fileName}" | ||
| 221 | + : Path.Combine(filePath, fileName); | ||
| 210 | var stream = file.OpenReadStream(); | 222 | var stream = file.OpenReadStream(); |
| 211 | switch (fileStoreType) | 223 | switch (fileStoreType) |
| 212 | { | 224 | { |
| @@ -229,9 +241,16 @@ namespace NCC.System.Service.Common | @@ -229,9 +241,16 @@ namespace NCC.System.Service.Common | ||
| 229 | break; | 241 | break; |
| 230 | } | 242 | } |
| 231 | } | 243 | } |
| 232 | - catch (Exception) | 244 | + catch (Exception ex) |
| 233 | { | 245 | { |
| 234 | - throw NCCException.Oh(ErrorCode.D8003); | 246 | + // 记录详细错误信息以便调试 |
| 247 | + var errorMsg = $"文件上传失败: {ex.Message}"; | ||
| 248 | + if (ex.InnerException != null) | ||
| 249 | + { | ||
| 250 | + errorMsg += $", InnerException: {ex.InnerException.Message}"; | ||
| 251 | + } | ||
| 252 | + // 抛出包含详细信息的异常 | ||
| 253 | + throw NCCException.Oh($"[D8003] {errorMsg}"); | ||
| 235 | } | 254 | } |
| 236 | } | 255 | } |
| 237 | 256 | ||
| @@ -240,14 +259,15 @@ namespace NCC.System.Service.Common | @@ -240,14 +259,15 @@ namespace NCC.System.Service.Common | ||
| 240 | /// </summary> | 259 | /// </summary> |
| 241 | /// <param name="filePath"></param> | 260 | /// <param name="filePath"></param> |
| 242 | /// <param name="fileDownLoadName"></param> | 261 | /// <param name="fileDownLoadName"></param> |
| 262 | + /// <param name="forceStoreType">强制使用指定的存储类型(如:aliyun-oss),如果为空则使用配置的存储类型</param> | ||
| 243 | /// <returns></returns> | 263 | /// <returns></returns> |
| 244 | [NonAction] | 264 | [NonAction] |
| 245 | - public async Task<FileStreamResult> DownloadFileByType(string filePath, string fileDownLoadName) | 265 | + public async Task<FileStreamResult> DownloadFileByType(string filePath, string fileDownLoadName, string forceStoreType = null) |
| 246 | { | 266 | { |
| 247 | try | 267 | try |
| 248 | { | 268 | { |
| 249 | var bucketName = KeyVariable.BucketName; | 269 | var bucketName = KeyVariable.BucketName; |
| 250 | - var fileStoreType = KeyVariable.FileStoreType; | 270 | + var fileStoreType = !string.IsNullOrEmpty(forceStoreType) ? forceStoreType : KeyVariable.FileStoreType; |
| 251 | switch (fileStoreType) | 271 | switch (fileStoreType) |
| 252 | { | 272 | { |
| 253 | case "minio": | 273 | case "minio": |
| @@ -255,7 +275,7 @@ namespace NCC.System.Service.Common | @@ -255,7 +275,7 @@ namespace NCC.System.Service.Common | ||
| 255 | var stream1 = await url1.GetAsStreamAsync(); | 275 | var stream1 = await url1.GetAsStreamAsync(); |
| 256 | return new FileStreamResult(stream1, "application/octet-stream") { FileDownloadName = fileDownLoadName }; | 276 | return new FileStreamResult(stream1, "application/octet-stream") { FileDownloadName = fileDownLoadName }; |
| 257 | case "aliyun-oss": | 277 | case "aliyun-oss": |
| 258 | - var url2 = await _oSSServiceFactory.Create("Aliyun").PresignedGetObjectAsync(bucketName, filePath, 86400); | 278 | + var url2 = await _oSSServiceFactory.Create("aliyun").PresignedGetObjectAsync(bucketName, filePath, 86400); |
| 259 | var stream2 = await url2.GetAsStreamAsync(); | 279 | var stream2 = await url2.GetAsStreamAsync(); |
| 260 | return new FileStreamResult(stream2, "application/octet-stream") { FileDownloadName = fileDownLoadName }; | 280 | return new FileStreamResult(stream2, "application/octet-stream") { FileDownloadName = fileDownLoadName }; |
| 261 | case "tencent-cos": | 281 | case "tencent-cos": |
| @@ -299,6 +319,8 @@ namespace NCC.System.Service.Common | @@ -299,6 +319,8 @@ namespace NCC.System.Service.Common | ||
| 299 | return FileVariable.SystemFilePath; | 319 | return FileVariable.SystemFilePath; |
| 300 | case "annexpic": | 320 | case "annexpic": |
| 301 | return FileVariable.SystemFilePath; | 321 | return FileVariable.SystemFilePath; |
| 322 | + case "annexpic_bak": | ||
| 323 | + return FileVariable.SystemFilePath; | ||
| 302 | case "document": | 324 | case "document": |
| 303 | return FileVariable.DocumentFilePath; | 325 | return FileVariable.DocumentFilePath; |
| 304 | case "diskdocument": | 326 | case "diskdocument": |