验证存储桶是否可访问

This commit is contained in:
zpc 2026-02-20 15:10:15 +08:00
parent 09f72d1132
commit d098a7ff81
3 changed files with 113 additions and 4 deletions

View File

@ -1,3 +1,6 @@
using COSXML;
using COSXML.Auth;
using COSXML.Model.Bucket;
using MiAssessment.Admin.Filters;
using MiAssessment.Admin.Models.Common;
using MiAssessment.Admin.Models.Config;
@ -93,4 +96,77 @@ public class ConfigController : ControllerBase
return ApiResponse<bool>.Error(AdminErrorCodes.InternalError, "更新上传配置失败");
}
}
/// <summary>
/// 测试腾讯云COS连接
/// </summary>
/// <param name="request">上传配置</param>
/// <returns>测试结果</returns>
[HttpPost("upload/testConnection")]
public Task<ApiResponse<bool>> TestCosConnection([FromBody] UploadSetting request)
{
// 验证必填参数
if (request.Type != "3")
{
return Task.FromResult(ApiResponse<bool>.Error(AdminErrorCodes.InvalidParameter, "仅支持测试腾讯云COS连接"));
}
if (string.IsNullOrWhiteSpace(request.AccessKeyId) ||
string.IsNullOrWhiteSpace(request.AccessKeySecret) ||
string.IsNullOrWhiteSpace(request.Bucket) ||
string.IsNullOrWhiteSpace(request.Region))
{
return Task.FromResult(ApiResponse<bool>.Error(AdminErrorCodes.InvalidParameter, "请填写完整的COS配置信息"));
}
try
{
// 创建COS客户端
var config = new CosXmlConfig.Builder()
.IsHttps(true)
.SetRegion(request.Region!)
.Build();
var credentialProvider = new DefaultQCloudCredentialProvider(
request.AccessKeyId!,
request.AccessKeySecret!,
600);
var cosXml = new CosXmlServer(config, credentialProvider);
// 尝试 HeadBucket 验证连接
var headBucketRequest = new HeadBucketRequest(request.Bucket!);
var result = cosXml.HeadBucket(headBucketRequest);
if (result.IsSuccessful())
{
return Task.FromResult(ApiResponse<bool>.Success(true, "连接成功"));
}
return Task.FromResult(ApiResponse<bool>.Error(AdminErrorCodes.InternalError, $"连接失败: {result.httpMessage}"));
}
catch (COSXML.CosException.CosClientException clientEx)
{
_logger.LogWarning(clientEx, "COS连接测试客户端错误");
return Task.FromResult(ApiResponse<bool>.Error(AdminErrorCodes.InternalError, $"连接失败: {clientEx.Message}"));
}
catch (COSXML.CosException.CosServerException serverEx)
{
_logger.LogWarning(serverEx, "COS连接测试服务端错误");
var message = serverEx.errorCode switch
{
"NoSuchBucket" => "存储桶不存在请检查Bucket名称",
"AccessDenied" => "访问被拒绝请检查SecretId和SecretKey",
"SignatureDoesNotMatch" => "签名不匹配请检查SecretKey",
"InvalidAccessKeyId" => "SecretId无效请检查配置",
_ => $"连接失败: {serverEx.errorCode} - {serverEx.errorMessage}"
};
return Task.FromResult(ApiResponse<bool>.Error(AdminErrorCodes.InternalError, message));
}
catch (Exception ex)
{
_logger.LogError(ex, "COS连接测试异常");
return Task.FromResult(ApiResponse<bool>.Error(AdminErrorCodes.InternalError, $"连接测试失败: {ex.Message}"));
}
}
}

View File

@ -44,3 +44,14 @@ export function updateUploadConfig(data: UploadSetting): Promise<ApiResponse<boo
data
})
}
/**
* COS连接
*/
export function testCosConnection(data: UploadSetting): Promise<ApiResponse<boolean>> {
return request<boolean>({
url: '/admin/config/upload/testConnection',
method: 'post',
data
})
}

View File

@ -135,7 +135,7 @@
<el-icon><Refresh /></el-icon>
重置
</el-button>
<el-button v-if="state.formData.type === '3'" @click="handleTest">
<el-button v-if="state.formData.type === '3'" :loading="state.testing" @click="handleTest">
<el-icon><Connection /></el-icon>
测试连接
</el-button>
@ -153,13 +153,14 @@
import { reactive, ref, computed, onMounted } from 'vue'
import { FolderOpened, Cloudy, Check, Refresh, Connection } from '@element-plus/icons-vue'
import { ElMessage, type FormInstance, type FormRules } from 'element-plus'
import { getUploadConfig, updateUploadConfig, type UploadSetting } from '@/api/system/config'
import { getUploadConfig, updateUploadConfig, testCosConnection, type UploadSetting } from '@/api/system/config'
// ============ Types ============
interface UploadConfigState {
loading: boolean
saving: boolean
testing: boolean
formData: UploadSetting
}
@ -172,6 +173,7 @@ const formRef = ref<FormInstance>()
const state = reactive<UploadConfigState>({
loading: false,
saving: false,
testing: false,
formData: {
type: '1',
appId: '',
@ -264,8 +266,28 @@ function handleReset() {
}
function handleTest() {
// TODO:
ElMessage.info('连接测试功能开发中')
//
if (!state.formData.accessKeyId || !state.formData.accessKeySecret ||
!state.formData.bucket || !state.formData.region) {
ElMessage.warning('请先填写完整的COS配置信息')
return
}
state.testing = true
testCosConnection(state.formData)
.then(res => {
if (res.code === 0) {
ElMessage.success(res.message || '连接成功')
} else {
ElMessage.error(res.message || '连接失败')
}
})
.catch(() => {
ElMessage.error('连接测试请求失败')
})
.finally(() => {
state.testing = false
})
}
// ============ Lifecycle ============