| | |
| | | HttpServletRequest request |
| | | ) { |
| | | log.info("接收参数bucketName:{}",bucketName); |
| | | // ===================== 1. 解析原始路径:保留所有斜杠/末尾分隔符,完全对齐原生MinIO ===================== |
| | | String rawUri = request.getRequestURI(); |
| | | String requestUri = URLDecoder.decode(rawUri, StandardCharsets.UTF_8); |
| | | // ===================== 核心修复:安全路径解析,替换替代截取,杜绝索引错误 ===================== |
| | | // String contextPath = request.getContextPath(); |
| | | String rawUri = URLDecoder.decode(request.getRequestURI(), StandardCharsets.UTF_8); |
| | | // 剔除上下文路径,得到纯业务路径 |
| | | String purePath = rawUri.substring("/minioTransfer".length()); |
| | | String bucketPrefix = "/" + bucketName; |
| | | // 提取原始ObjectKey,无任何修改 |
| | | String objectKey = requestUri.substring(bucketPrefix.length()); |
| | | |
| | | log.info("中转MinIO PUT请求 | 桶名:{} | 原始对象路径:{} | 请求体大小:{}byte", |
| | | bucketName, objectKey, rawRequestBody == null ? 0 : rawRequestBody.length); |
| | | log.info("中转MinIO 路径解析开始 | 原始URI:{} | 纯业务路径:{} | 桶前缀:{}", rawUri, purePath, bucketPrefix); |
| | | |
| | | // 校验路径是否以桶前缀开头 |
| | | if (!purePath.startsWith(bucketPrefix)) { |
| | | return buildNativeS3Error("InvalidRequest", "请求路径格式不匹配", rawUri, HttpStatus.BAD_REQUEST); |
| | | } |
| | | |
| | | // 修复点:replace替换前缀,替代 substring 长度截取,彻底解决索引错位问题 |
| | | String objectKey = purePath.replaceFirst("^" + bucketPrefix, ""); |
| | | // 兜底处理空路径 |
| | | if (objectKey.isEmpty()) { |
| | | objectKey = "/"; |
| | | } |
| | | |
| | | log.info("中转MinIO 路径解析成功 | 纯业务路径:{} | 桶名:{} | 最终对象路径:{}", |
| | | purePath, bucketName, objectKey); |
| | | |
| | | // byte[] requestData = rawRequestBody == null ? new byte[0] : rawRequestBody; |
| | | |
| | | try { |
| | | // ===================== 2. 复用原有逻辑:获取临时凭证 ===================== |
| | | var credentials = ossService.getCredentials(); |
| | | if (credentials == null || credentials.getAccessKeyId() == null || credentials.getSecurityToken() == null) { |
| | | log.error("临时凭证获取失败"); |
| | | return buildNativeS3Error("InvalidCredentials", "临时凭证无效", requestUri, HttpStatus.FORBIDDEN); |
| | | return buildNativeS3Error("InvalidCredentials", "临时凭证无效", rawUri, HttpStatus.FORBIDDEN); |
| | | } |
| | | |
| | | // ===================== 3. 复用原有逻辑:构建MinIO客户端 ===================== |
| | |
| | | // 校验桶存在性(兼容原生接口行为,桶不存在返回404) |
| | | boolean bucketExists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()); |
| | | if (!bucketExists) { |
| | | return buildNativeS3Error("NoSuchBucket", "指定存储桶不存在", requestUri, HttpStatus.NOT_FOUND); |
| | | return buildNativeS3Error("NoSuchBucket", "指定存储桶不存在", bucketName, HttpStatus.NOT_FOUND); |
| | | } |
| | | |
| | | // ===================== 4. 透传请求:原样转发大疆原始数据到MinIO,无业务篡改 ===================== |
| | |
| | | .body(nativeError); |
| | | } catch (MinioException e) { |
| | | log.error("MinIO客户端异常:{}", e.getMessage()); |
| | | return buildNativeS3Error("ClientError", e.getMessage(), requestUri, HttpStatus.INTERNAL_SERVER_ERROR); |
| | | return buildNativeS3Error("ClientError", e.getMessage(), rawUri, HttpStatus.INTERNAL_SERVER_ERROR); |
| | | } catch (Exception e) { |
| | | log.error("代理中转通用异常:{}", e.getMessage(), e); |
| | | return buildNativeS3Error("InternalError", "服务器代理异常", requestUri, HttpStatus.INTERNAL_SERVER_ERROR); |
| | | return buildNativeS3Error("InternalError", "服务器代理异常", rawUri, HttpStatus.INTERNAL_SERVER_ERROR); |
| | | } |
| | | } |
| | | |