全部文档
当前文档

暂无内容

如果没有找到您期望的内容,请尝试其他搜索词

文档中心

通过外链上传文件(Java)

最近更新时间:2025-04-29 14:35:02

简单上传

生成预签名链接

该方法为生成上传文件的预签名链接,用户可以使用该链接上传文件。

该方法上传的单文件大小不能超过5GB,超过5GB的文件请使用分块上传 。

// 初始化KS3Client,详情请参见文档:https://docs.ksyun.com/documents/40559
Ks3 client = initKs3Client();
GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest();
req.setMethod(HttpMethod.PUT);
// 文件上传的bucket
req.setBucket(bucket);
// 文件名
req.setKey(key);
// 不指定的话则默认为15分钟后过期
req.setExpiration(<生成的外链的过期时间>);
// 设置acl为公开读,不加该header则默认为私有,生成外链时设置了header,则在使用外链的时候也需要添加相应的header
req.getRequestConfig().getExtendHeaders().put("x-kss-acl", "public-read");
// 设置文件的Content-Type,具体值请根据时间情况设定。在使用外链的时候需要把Content-Type设置成指定的值
req.setContentType("application/octet-stream");
// req.setSseAlgorithm("AES256");  //设置服务端加密
String url = client.generatePresignedUrl(req);

使用预签名链接

当用户拿到该URL之后便可以通过以下代码上传文件。(请自行拆分uri和host)

PUT /{uri} HTTP/1.1
Host: {host}
Date: {当前时间}
x-kss-acl:public-read    //因为在生成外链的时候设置了该header,所以在发送的时候也需要带上
Content-Type:application/octet-stream   //同上
Content-Length:100
[100 bytes of data]

分块上传

1. 单文件大小大于5GB时必须采用分块上传。

2. 使用预签名链接时,请注意请求头必须与生成链接时的请求头一致,否则会有签名不一致的问题,原因是部分请求头会参与签名的计算,如:Content-TypeContent-MD5、以x-kss-开头的请求头等。

生成预签名链接

生成列举分块上传任务的预签名链接
/**
 * 生成列举分块上传任务的预签名链接
 *
 * @param bucketName   桶名
 * @param params     请求参数,如:prefix、delimiter、max-uploads、upload-id-marker、key-marker 等,可为空
 * @return  预签名链接
 */
public String generateListMultipartUploadsPresignedUrl(String bucketName, Map<String, String> params) {
    GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest();
    request.setBucket(bucketName);
    if (params != null) {
        request.setRequestParameters(params);
    }
    request.getRequestParameters().put("uploads", "");
    // 设置链接有效期为15分钟
    request.setExpiration(new Date(System.currentTimeMillis() + 15 * 60 * 1000));
    return ks3Client.generatePresignedUrl(request);
}
生成列举指定上传任务中所有已上传块的预签名链接
/**
 * 生成列举指定上传任务中所有已上传块的预签名链接
 *
 * @param bucketName   桶名
 * @param objectKey  对象名
 * @param uploadId   分块上传 ID
 * @param params     请求参数,如:max-parts、part-number-marker 等,可为空
 * @return    预签名链接
 */
public String generateListPartsPresignedUrl(String bucketName, String objectKey, String uploadId, Map<String, String> params) {
    GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest();
    request.setBucket(bucketName);
    request.setKey(objectKey);
    if (params != null) {
        request.setRequestParameters(params);
    }
    request.getRequestParameters().put("uploadId", uploadId);
    // 设置链接有效期为15分钟
    request.setExpiration(new Date(System.currentTimeMillis() + 15 * 60 * 1000));
    return ks3Client.generatePresignedUrl(request);
}
生成初始化分块上传的预签名链接
/**
 * 生成初始化分块上传的预签名链接
 *
 * @param bucketName   桶名
 * @param objectKey  对象名
 * @param headers    请求头
 * @return   预签名链接
 */
public String generateInitMultipartUploadPresignedUrl(String bucketName, String objectKey, Map<String, String> headers) {
    GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest();
    request.setBucket(bucketName);
    request.setKey(objectKey);
    request.setMethod(HttpMethod.POST);
    request.getRequestParameters().put("uploads", "");
    request.getRequestConfig().setExtendHeaders(headers);
    // 设置链接有效期为15分钟
    request.setExpiration(new Date(System.currentTimeMillis() + 15 * 60 * 1000));
    return ks3Client.generatePresignedUrl(request);
}
生成上传分块的预签名链接
/**
 * 生成上传分块的预签名链接
 *
 * @param bucketName   桶名
 * @param objectKey  对象名
 * @param uploadId   分块上传ID
 * @param partNumber   分块号
 * @return   预签名链接
 */
public String generateUploadPartPresignedUrl(String bucketName, String objectKey, String uploadId, int partNumber) {
    GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest();
    request.setBucket(bucketName);
    request.setKey(objectKey);
    request.setMethod(HttpMethod.PUT);
    request.getRequestParameters().put("partNumber", String.valueOf(partNumber));
    request.getRequestParameters().put("uploadId", uploadId);
    // 设置链接有效期为15分钟
    request.setExpiration(new Date(System.currentTimeMillis() + 15 * 60 * 1000));
    return ks3Client.generatePresignedUrl(request);
}
生成完成分块上传的预签名链接
/**
 * 生成完成分块上传的预签名链接
 *
 * @param bucketName   桶名
 * @param objectKey   对象名
 * @param uploadId   分块上传 ID
 * @return   预签名链接
 */
public String generateCompleteMultipartUploadPresignedUrl(String bucketName, String objectKey, String uploadId) {
    GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest();
    request.setBucket(bucketName);
    request.setKey(objectKey);
    request.setMethod(HttpMethod.POST);
    request.getRequestParameters().put("uploadId", uploadId);
    // 设置请求头,使用该链接时需要带上以下请求头
    request.getRequestConfig().getExtendHeaders().put("Content-Type", "application/xml");
    // 设置链接有效期为15分钟
    request.setExpiration(new Date(System.currentTimeMillis() + 15 * 60 * 1000));
    return ks3Client.generatePresignedUrl(request);
}
生成终止分块上传任务的预签名链接
/**
 * 生成终止分块上传任务的预签名链接
 *
 * @param bucketName   桶名
 * @param objectKey   对象名
 * @param uploadId    分块上传ID
 * @return   预签名链接
 */
public String generateAbortMultipartUploadPresignedUrl(String bucketName, String objectKey, String uploadId) {
    GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest();
    request.setBucket(bucketName);
    request.setKey(objectKey);
    request.setMethod(HttpMethod.DELETE);
    request.getRequestParameters().put("uploadId", uploadId);
    request.setExpiration(new Date(System.currentTimeMillis() + 15 * 60 * 1000));
    return ks3Client.generatePresignedUrl(request);
}

使用预签名链接

使用预签名链接初始化分块
/**
 * 使用预签名链接初始化分块
 *
 * @param url        预签名链接
 * @param headers    请求头
 * @param httpClient         http客户端
 * @return uploadId           分块任务ID
 * @throws IOException    IO异常
 */
public String initMultipartUpload(String url, Map<String, String> headers, CloseableHttpClient httpClient) throws IOException {
    HttpPost httpInit = new HttpPost(url);
    for (Map.Entry<String, String> entry : headers.entrySet()) {
        httpInit.setHeader(entry.getKey(), entry.getValue());
    }
    try (CloseableHttpResponse response = httpClient.execute(httpInit)) {
        String content = StringUtils.inputStream2String(response.getEntity().getContent());
        if (response.getStatusLine().getStatusCode() != 200) {
            throw new RuntimeException("Init multipart upload failed, response: " + content);
        }
        // 解析返回的xml获取uploadId
        int startIndex = content.indexOf("<UploadId>");
        int endIndex = content.indexOf("</UploadId>");
        return content.substring(startIndex + "<UploadId>".length(), endIndex);
    }
}

使用预签名链接上传分块
/**
 * 使用预签名链接上传分块
 *
 * @param url         预签名链接
 * @param file         文件
 * @param partNumber      分块号
 * @param partSize     分块大小
 * @param httpClient http     客户端
 * @return partETag     分块的ETag值
 * @throws IOException      IO异常
 */
public Map<String, String> uploadPart(String url, File file, int partNumber, long partSize, CloseableHttpClient httpClient) throws IOException {
    // 获取文件流
    long fileLength = file.length();
    long offset = (partNumber - 1) * partSize;
    long currentPartSize = Math.min(partSize, fileLength - offset);
    FileInputStream fileInputStream = new FileInputStream(file);
    fileInputStream.skip(offset);

    // 生成请求体
    BasicHttpEntity httpEntity = new BasicHttpEntity();
    httpEntity.setContent(fileInputStream);
    httpEntity.setContentLength(currentPartSize);
    HttpPut httpPut = new HttpPut(url);
    httpPut.setEntity(httpEntity);

    // 上传分块
    try (CloseableHttpResponse response = httpClient.execute(httpPut)) {
        if (response.getStatusLine().getStatusCode() != 200) {
            String content = "";
            if (response.getEntity() != null && response.getEntity().getContent() != null) {
                content = StringUtils.inputStream2String(response.getEntity().getContent());
            }
            throw new RuntimeException("Upload part failed, status code: " + response.getStatusLine().getStatusCode() + ", response: " + content);
        }
        // 解析响应头获取ETag、crc64
        String crc64 = response.getFirstHeader("x-kss-checksum-crc64ecma").getValue();
        String eTag = response.getFirstHeader("ETag").getValue();
        Map<String, String> partETag = new HashMap<>();
        partETag.put("PartNumber", String.valueOf(partNumber));
        partETag.put("ETag", eTag);
        partETag.put("crc64", crc64);
        return partETag;
    }
}
使用预签名链接完成分块上传
/**
 * 使用预签名链接完成分块上传
 *
 * @param url        预签名链接
 * @param partETags          分块ETag
 * @param httpClient          http客户端
 * @throws IOException     IO异常
 */
public void completeMultipartUpload(String url, List<Map<String, String>> partETags, CloseableHttpClient httpClient) throws IOException {
    // 生成 CompleteMultipartUpload 请求的 xml
    StringBuilder completeXml = new StringBuilder();
    completeXml.append("<CompleteMultipartUpload>");
    for (Map<String, String> partETag : partETags) {
        completeXml.append("<Part>");
        completeXml.append("<PartNumber>").append(partETag.get("PartNumber")).append("</PartNumber>");
        completeXml.append("<ETag>").append(partETag.get("ETag")).append("</ETag>");
        completeXml.append("<ChecksumCRC64ECMA>").append(partETag.get("crc64")).append("</ChecksumCRC64ECMA>");
        completeXml.append("</Part>");
    }
    completeXml.append("</CompleteMultipartUpload>");

    // 设置请求体
    byte[] bytes = completeXml.toString().getBytes(StandardCharsets.UTF_8);
    int length = bytes.length;
    ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
    BasicHttpEntity httpEntity = new BasicHttpEntity();
    httpEntity.setContent(inputStream);
    httpEntity.setContentLength(length);

    HttpPost httpPost = new HttpPost(url);
    httpPost.setHeader("Content-Type", "application/xml");
    httpPost.setEntity(httpEntity);

    // 发送CompleteMultipartUpload请求
    try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode != 200) {
            String content = "";
            if (response.getEntity() != null && response.getEntity().getContent() != null) {
                content = StringUtils.inputStream2String(response.getEntity().getContent());
            }
            throw new RuntimeException("Complete multipart upload failed, status code: " + statusCode + ", response: " + content);
        }
    }
}

使用预签名链接分块上传文件的完整示例
/**
 * 使用预签名链接分块上传文件的完整示例
 *
 * @param bucketName      桶名
 * @param objectKey     对象名
 * @param file     本地文件
 */
public void uploadFileByMultipartUploadPreSignedUrls(String bucketName, String objectKey, File file) {
    try (CloseableHttpClient httpClient = HttpClients.createDefault()) {

        // 1. 初始化分块上传
        Map<String, String> headers = new HashMap<>();
        // 设置存储类型
        headers.put("x-kss-storage-class", "STANDARD");
        // 设置访问权限
        headers.put("x-kss-acl", "private");
        // 设置禁止覆盖
        headers.put("x-kss-forbid-overwrite", "false");
        // 设置标签
        headers.put("x-kss-tagging", "key1=value1&key2=value2");
        // 设置自定义元数据
        headers.put("x-kss-meta-key1", "value1");
        // 设置内容类型
        headers.put("Content-Type", "text/plain");
        // 生成初始化分块上传的预签名链接
        String initUrl = generateInitMultipartUploadPresignedUrl(bucketName, objectKey, headers);
        // 初始化分块上传,获取uploadId。注意:务必带上生成预签名链接时设置的请求头
        String uploadId = initMultipartUpload(initUrl, headers, httpClient);
        log.info("Init multipart upload successfully, uploadId: " + uploadId);

        // 2. 上传分块
        long partSize = 50 * 1024 * 1024;
        long fileLength = file.length();
        // 计算分块数量
        int partCount = (int) (fileLength / partSize);
        if (fileLength % partSize != 0) {
            partCount++;
        }

        List<Map<String, String>> partETags = new ArrayList<>();
        for (int i = 0; i < partCount; i++) {
            // 计算分块号、偏移量、当前分块大小,分块号从 1 开始
            int partNumber = i + 1;
            long offset = i * partSize;
            long currentPartSize = Math.min(partSize, fileLength - offset);
            log.info("Uploading part " + partNumber);
            // 生成上传分块的预签名链接
            String uploadPartPresignedUrl = generateUploadPartPresignedUrl(bucketName, objectKey, uploadId, partNumber);
            // 上传分块,获取partETag
            Map<String, String> partETag = uploadPart(uploadPartPresignedUrl, file, partNumber, currentPartSize, httpClient);
            log.info("Upload part " + partNumber + " successfully");
            partETags.add(partETag);
        }

        // 3. 完成分块上传
        String completeUrl = generateCompleteMultipartUploadPresignedUrl(bucketName, objectKey, uploadId);
        completeMultipartUpload(completeUrl, partETags, httpClient);
        log.info("Upload file by multipart upload pre-signed urls successfully");
    } catch (IOException e) {
        log.error("Upload file by multipart upload pre-signed urls failed", e);
    }
}

文档导读
纯净模式常规模式

纯净模式

点击可全屏预览文档内容
文档反馈