OSS在完成文件(Object)上传时可以提供回调(Callback)给应用服务器。您只需要在发送给OSS的请求中携带相应的Callback参数,即可实现上传回调。
注意事项
本文以华东1(杭州)外网Endpoint为例。如果您希望通过与OSS同地域的其他阿里云产品访问OSS,请使用内网Endpoint。关于OSS支持的Region与Endpoint的对应关系,请参见OSS地域和访问域名。
本文以从环境变量读取访问凭证为例。如何配置访问凭证,请参见Java配置访问凭证。
本文以OSS域名新建OSSClient为例。如果您希望通过自定义域名、STS等方式新建OSSClient,请参见常见场景配置示例。
示例代码
简单上传文件并设置回调
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.Callback;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import java.io.ByteArrayInputStream;
public class Demo {
public static void main(String[] args) throws Exception{
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 填写Bucket名称,例如examplebucket。
String bucketName = "examplebucket";
// 填写Object完整路径,例如exampledir/exampleobject.txt。Object完整路径中不能包含Bucket名称。
String objectName = "exampledir/exampleobject.txt";
// 您的回调服务器地址,例如https://example.com:23450。
String callbackUrl = "yourCallbackServerUrl";
// 填写Bucket所在地域。以华东1(杭州)为例,Region填写为cn-hangzhou。
String region = "cn-hangzhou";
// 创建OSSClient实例。
// 当OSSClient实例不再使用时,调用shutdown方法以释放资源。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
try {
String content = "Hello OSS";
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName,new ByteArrayInputStream(content.getBytes()));
// 配置上传回调参数
Callback callback = new Callback();
callback.setCallbackUrl(callbackUrl);
//(可选)设置回调请求消息头中Host的值,即您的服务器配置Host的值。
// callback.setCallbackHost("yourCallbackHost");
// 设置回调请求的 Body 内容,采用 JSON 格式,并在其中定义占位符变量。
callback.setCalbackBodyType(Callback.CalbackBodyType.JSON);
callback.setCallbackBody("{\\\"bucket\\\":${bucket},\\\"object\\\":${object},\\\"mimeType\\\":${mimeType},\\\"size\\\":${size},\\\"my_var1\\\":${x:var1},\\\"my_var2\\\":${x:var2}}");
// 设置发起回调请求的自定义参数,由Key和Value组成,Key必须以x:开始。
callback.addCallbackVar("x:var1", "value1");
callback.addCallbackVar("x:var2", "value2");
putObjectRequest.setCallback(callback);
// 执行上传操作
PutObjectResult putObjectResult = ossClient.putObject(putObjectRequest);
// 读取上传回调返回的消息内容。
byte[] buffer = new byte[1024];
putObjectResult.getResponse().getContent().read(buffer);
// 数据读取完成后,获取的流必须关闭,否则会造成连接泄漏,导致请求无连接可用,程序无法正常工作。
putObjectResult.getResponse().getContent().close();
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (Throwable ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
}
分片上传文件并设置回调
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.internal.Mimetypes;
import com.aliyun.oss.model.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
public class Demo {
public static void main(String[] args) throws Exception {
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 填写Bucket名称,例如examplebucket。
String bucketName = "examplebucket";
// 填写Object完整路径,例如exampledir/exampleobject.txt。Object完整路径中不能包含Bucket名称。
String objectName = "exampledir/exampleobject.txt";
// 待上传本地文件路径。
String filePath = "D:\\localpath\\examplefile.txt";
// 填写Bucket所在地域。以华东1(杭州)为例,Region填写为cn-hangzhou。
String region = "cn-hangzhou";
// 您的回调服务器地址,例如https://example.com:23450。
String callbackUrl = "https://example.com:23450";
// 创建OSSClient实例。
// 当OSSClient实例不再使用时,调用shutdown方法以释放资源。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
try {
// 创建InitiateMultipartUploadRequest对象。
InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, objectName);
// 设置Object的元数据,并获取文件的Content-Type。
ObjectMetadata metadata = new ObjectMetadata();
if (metadata.getContentType() == null) {
metadata.setContentType(Mimetypes.getInstance().getMimetype(new File(filePath), objectName));
}
System.out.println("Content-Type: " + metadata.getContentType());
// 将metadata绑定到上传请求中。
request.setObjectMetadata(metadata);
// 初始化分片。
InitiateMultipartUploadResult upresult = ossClient.initiateMultipartUpload(request);
// 返回uploadId。
String uploadId = upresult.getUploadId();
// partETags是PartETag的集合。PartETag由分片的ETag和分片号组成。
List<PartETag> partETags = new ArrayList<PartETag>();
// 每个分片的大小,用于计算文件有多少个分片。单位为字节。
// 分片最小值为100 KB,最大值为5 GB。最后一个分片的大小允许小于100 KB。
// 设置分片大小为 1 MB。
final long partSize = 1 * 1024 * 1024L;
// 根据上传的数据大小计算分片数。以本地文件为例,说明如何通过File.length()获取上传数据的大小。
final File sampleFile = new File(filePath);
long fileLength = sampleFile.length();
int partCount = (int) (fileLength / partSize);
if (fileLength % partSize != 0) {
partCount++;
}
// 遍历分片上传。
for (int i = 0; i < partCount; i++) {
long startPos = i * partSize;
long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize;
UploadPartRequest uploadPartRequest = new UploadPartRequest();
uploadPartRequest.setBucketName(bucketName);
uploadPartRequest.setKey(objectName);
uploadPartRequest.setUploadId(uploadId);
// 设置上传的分片流。
// 以本地文件为例说明如何创建FileInputStream,并通过InputStream.skip()方法跳过指定数据。
InputStream instream = new FileInputStream(sampleFile);
instream.skip(startPos);
uploadPartRequest.setInputStream(instream);
// 设置分片大小。
uploadPartRequest.setPartSize(curPartSize);
// 设置分片号。每一个上传的分片都有一个分片号,取值范围是1~10000,如果超出此范围,OSS将返回InvalidArgument错误码。
uploadPartRequest.setPartNumber(i + 1);
// 每个分片不需要按顺序上传,甚至可以在不同客户端上传,OSS会按照分片号排序组成完整的文件。
UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
// 每次上传分片之后,OSS的返回结果包含PartETag。PartETag将被保存在partETags中。
partETags.add(uploadPartResult.getPartETag());
// 关闭流
instream.close();
}
// 创建CompleteMultipartUploadRequest对象。
// 在执行完成分片上传操作时,需要提供所有有效的partETags。OSS收到提交的partETags后,会逐一验证每个分片的有效性。当所有的数据分片验证通过后,OSS将把这些分片组合成一个完整的文件。
CompleteMultipartUploadRequest completeMultipartUploadRequest =
new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags);
// 设置上传回调参数。
Callback callback = new Callback();
callback.setCallbackUrl(callbackUrl);
//(可选)设置回调请求消息头中Host的值,即您的服务器配置Host的值。
// callback.setCallbackHost("yourCallbackHost");
// 设置回调请求的Body内容,采用JSON格式,并定义回调Body的占位符变量。
callback.setCalbackBodyType(Callback.CalbackBodyType.JSON);
callback.setCallbackBody("{\\\"bucket\\\":${bucket},\\\"object\\\":${object},\\\"mimeType\\\":${mimeType},\\\"size\\\":${size},\\\"my_var1\\\":${x:var1},\\\"my_var2\\\":${x:var2}}");
// 设置发起回调请求的自定义参数,由Key和Value组成,Key必须以x:开始。
callback.addCallbackVar("x:var1", "value1");
callback.addCallbackVar("x:var2", "value2");
completeMultipartUploadRequest.setCallback(callback);
// 完成分片上传。
CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest);
System.out.println("上传成功,ETag:" + completeMultipartUploadResult.getETag());
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught a ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
}
表单上传文件并设置回调
import com.aliyun.oss.ClientException;
import com.aliyun.oss.common.auth.ServiceSignature;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.common.utils.StringUtils;
import com.aliyun.oss.internal.OSSUtils;
import com.aliyun.oss.model.Callback;
import org.apache.commons.codec.binary.Base64;
import javax.activation.MimetypesFileTypeMap;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
public class PostObjectCallbackV4Demo {
// 填写待上传的本地文件的完整路径。
private static final String localFilePath = "D:\\localpath\\examplefile.txt";
// Endpoint以杭州为例,其它Region请按实际情况填写。
private static final String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。
private static final String accessKeyId = System.getenv("OSS_ACCESS_KEY_ID");
private static final String accessKeySecret = System.getenv("OSS_ACCESS_KEY_SECRET");
// 填写Bucket名称,例如examplebucket。
private static final String bucketName = "examplebucket";
// 填写Object完整路径,例如exampledir/exampleobject.txt。Object完整路径中不能包含Bucket名称。
private static final String objectName = "exampledir/exampleobject.txt";
// 设置回调服务器地址,例如http://oss-demo.oss-cn-hangzhou.aliyuncs.com:23450或http://127.0.0.1:9090。
private static final String callbackServerUrl = "http://oss-demo.oss-cn-hangzhou.aliyuncs.com:23450";
// 设置回调请求消息头中Host的值,例如oss-cn-hangzhou.aliyuncs.com。
private static final String callbackServerHost = "";
// 填写Bucket所在地域。以华东1(杭州)为例,Region填写为cn-hangzhou。
private static final String region = "cn-hangzhou";
private static Date requestDateTime = new Date();
/**
* 表单上传。
* @throws Exception
*/
private void PostObject() throws Exception {
// 在URL中添加Bucket名称,添加后URL格式为http://yourBucketName.oss-cn-hangzhou.aliyuncs.com。
String urlStr = endpoint.replace("http://", "http://" + bucketName+ ".");
// 构造表单参数
Map<String, String> formFields = new LinkedHashMap<String, String>();
formFields.put("key", objectName);
formFields.put("Content-Disposition", "attachment;filename="
+ localFilePath);
// 设置回调参数。
Callback callback = new Callback();
// 设置回调服务器地址,例如http://oss-demo.oss-cn-hangzhou.aliyuncs.com:23450或http://127.0.0.1:9090。
callback.setCallbackUrl(callbackServerUrl);
// 设置回调请求消息头中Host的值,如oss-cn-hangzhou.aliyuncs.com。
callback.setCallbackHost(callbackServerHost);
// 设置回调请求的Body内容,采用JSON格式,并定义回调Body的占位符变量。
callback.setCalbackBodyType(Callback.CalbackBodyType.JSON);
callback.setCallbackBody("{\\\"bucket\\\":${bucket},\\\"object\\\":${object},\\\"mimeType\\\":${mimeType},\\\"size\\\":${size},\\\"my_var1\\\":${x:var1},\\\"my_var2\\\":${x:var2}}");
// 设置发起回调请求的自定义参数,由Key和Value组成,Key必须以x:开始,且必须小写。
callback.addCallbackVar("x:var1", "value1");
callback.addCallbackVar("x:var2", "value2");
// 在表单Map中设置回调参数。
setCallBack(formFields, callback);
// 设置OSSAccessKeyId。
formFields.put("OSSAccessKeyId", accessKeyId);
String policy = "{\"expiration\": \"2120-01-01T12:00:00.000Z\",\"conditions\": [" +
" {\"x-oss-signature-version\": \"OSS4-HMAC-SHA256\"},\n" +
" {\"x-oss-credential\": \""+accessKeyId+"/"+getDate()+"/"+region+"/oss/aliyun_v4_request\"},\n" +
" {\"x-oss-date\": \""+getDateTime()+"\"},\n" +
" [\"content-length-range\", 0, 104857600]" +
"]}";
String encodePolicy = new String(Base64.encodeBase64(policy.getBytes()));
// 设置policy。
formFields.put("policy", encodePolicy);
System.out.println("policy:" + policy);
// 生成签名。
formFields.put("x-oss-signature-version", "OSS4-HMAC-SHA256");
formFields.put("x-oss-credential", accessKeyId+"/"+getDate()+"/"+region+"/oss/aliyun_v4_request");
formFields.put("x-oss-date", getDateTime());
String stringToSign = new String(Base64.encodeBase64(policy.getBytes()));
System.out.println("stringToSign:" + stringToSign);
byte[] signingKey = buildSigningKey();
String signature = buildSignature(signingKey, stringToSign);
formFields.put("x-oss-signature", signature);
System.out.println("Signature:" + signature);
// 执行上传
String ret = formUpload(urlStr, formFields);
System.out.println("Post Object [" + objectName + "] to bucket [" + bucketName + "]");
System.out.println("post reponse:" + ret);
}
private static String formUpload(String urlStr, Map<String, String> formFields)
throws Exception {
String res = "";
HttpURLConnection conn = null;
String boundary = "9431149156168";
try {
URL url = new URL(urlStr);
conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(30000);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("User-Agent",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");
conn.setRequestProperty("Content-Type",
"multipart/form-data; boundary=" + boundary);
// 处理表单字段
OutputStream out = new DataOutputStream(conn.getOutputStream());
// 遍历读取表单Map中的数据,将数据写入到输出流中。
if (formFields != null) {
StringBuilder strBuf = new StringBuilder();
Iterator<Map.Entry<String, String>> iter = formFields.entrySet().iterator();
int i = 0;
while (iter.hasNext()) {
Map.Entry<String, String> entry = iter.next();
String inputName = entry.getKey();
String inputValue = entry.getValue();
if (inputValue == null) {
continue;
}
if (i == 0) {
strBuf.append("--").append(boundary).append("\r\n");
strBuf.append("Content-Disposition: form-data; name=\"").append(inputName).append("\"\r\n\r\n");
strBuf.append(inputValue);
} else {
strBuf.append("\r\n").append("--").append(boundary).append("\r\n");
strBuf.append("Content-Disposition: form-data; name=\""
+ inputName + "\"\r\n\r\n");
strBuf.append(inputValue);
}
i++;
}
out.write(strBuf.toString().getBytes());
}
// 读取文件信息,将要上传的文件写入到输出流中。
File file = new File(localFilePath);
String filename = file.getName();
String contentType = new MimetypesFileTypeMap().getContentType(file);
if (contentType == null || contentType.equals("")) {
contentType = "application/octet-stream";
}
StringBuffer strBuf = new StringBuffer();
strBuf.append("\r\n").append("--").append(boundary)
.append("\r\n");
strBuf.append("Content-Disposition: form-data; name=\"file\"; "
+ "filename=\"" + filename + "\"\r\n");
strBuf.append("Content-Type: " + contentType + "\r\n\r\n");
out.write(strBuf.toString().getBytes());
DataInputStream in = new DataInputStream(new FileInputStream(file));
int bytes = 0;
byte[] bufferOut = new byte[1024];
while ((bytes = in.read(bufferOut)) != -1) {
out.write(bufferOut, 0, bytes);
}
in.close();
byte[] endData = ("\r\n--" + boundary + "--\r\n").getBytes();
out.write(endData);
out.flush();
out.close();
// 读取返回数据。
strBuf = new StringBuffer();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null) {
strBuf.append(line).append("\n");
}
res = strBuf.toString();
reader.close();
reader = null;
} catch (ClientException e) {
System.err.println("Send post request exception: " + e);
System.err.println(e.getErrorCode()+" msg="+e.getMessage());
throw e;
} finally {
if (conn != null) {
conn.disconnect();
conn = null;
}
}
return res;
}
private static void setCallBack(Map<String, String> formFields, Callback callback) {
if (callback != null) {
String jsonCb = OSSUtils.jsonizeCallback(callback);
String base64Cb = BinaryUtil.toBase64String(jsonCb.getBytes());
formFields.put("callback", base64Cb);
if (callback.hasCallbackVar()) {
Map<String, String> varMap = callback.getCallbackVar();
for (Map.Entry<String, String> entry : varMap.entrySet()) {
formFields.put(entry.getKey(), entry.getValue());
}
}
}
}
private static String getDateTime() {
return getIso8601DateTimeFormat().format(requestDateTime);
}
private static DateFormat getIso8601DateTimeFormat() {
SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'", Locale.US);
df.setTimeZone(new SimpleTimeZone(0, "GMT"));
return df;
}
private static DateFormat getIso8601DateFormat() {
SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd", Locale.US);
df.setTimeZone(new SimpleTimeZone(0, "GMT"));
return df;
}
private static String getDate() {
return getIso8601DateFormat().format(requestDateTime);
}
private String buildSignature(byte[] signingKey, String stringToSign) {
byte[] result = ServiceSignature.create("HmacSHA256").computeHash(signingKey, stringToSign.getBytes(StringUtils.UTF8));
return BinaryUtil.toHex(result);
}
private byte[] buildSigningKey() {
ServiceSignature signature = ServiceSignature.create("HmacSHA256");
byte[] signingSecret = ("aliyun_v4" + accessKeySecret).getBytes(StringUtils.UTF8);
byte[] signingDate = signature.computeHash(signingSecret, getDate().getBytes(StringUtils.UTF8));
byte[] signingRegion = signature.computeHash(signingDate, region.getBytes(StringUtils.UTF8));
byte[] signingService = signature.computeHash(signingRegion, "oss".getBytes(StringUtils.UTF8));
/*System.out.println("signingSecret:\n" + BinaryUtil.toHex(signingSecret));
System.out.println("signingDate:\n" + BinaryUtil.toHex(signingDate));
System.out.println("signingRegion:\n" + BinaryUtil.toHex(signingRegion));
System.out.println("signingService:\n" + BinaryUtil.toHex(signingService));*/
return signature.computeHash(signingService, "aliyun_v4_request".getBytes(StringUtils.UTF8));
}
public static void main(String[] args) throws Exception {
PostObjectCallbackV4Demo ossPostObject = new PostObjectCallbackV4Demo();
ossPostObject.PostObject();
}
}
断点续传上传文件并设置回调
package Callback;
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.internal.Mimetypes;
import com.aliyun.oss.model.*;
import java.io.File;
public class Demo {
public static void main(String[] args) throws Exception {
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 填写Bucket名称,例如examplebucket。
String bucketName = "examplebucket";
// 填写Object完整路径,例如exampledir/exampleobject.txt。Object完整路径中不能包含Bucket名称。
String objectName = "exampledir/exampleobject.txt";
// 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
String filePath = "D:\\localpath\\examplefile.txt";
// 填写Bucket所在地域。以华东1(杭州)为例,Region填写为cn-hangzhou。
String region = "cn-hangzhou";
// 您的回调服务器地址,例如https://example.com:23450。
String callbackUrl = "http://example.com:23450/callback";
// 创建OSSClient实例。
// 当OSSClient实例不再使用时,调用shutdown方法以释放资源。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
try {
// 设置Object的元数据,并获取文件的Content-Type。
ObjectMetadata metadata = new ObjectMetadata();
if (metadata.getContentType() == null) {
metadata.setContentType(Mimetypes.getInstance().getMimetype(new File(filePath), objectName));
}
System.out.println("Content-Type: " + metadata.getContentType());
// 通过UploadFileRequest设置多个参数。
// 依次填写Bucket名称(例如examplebucket)以及Object完整路径(例如exampledir/exampleobject.txt),Object完整路径中不能包含Bucket名称。
UploadFileRequest uploadFileRequest = new UploadFileRequest(bucketName,objectName);
// 通过UploadFileRequest设置单个参数。
// 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。
uploadFileRequest.setUploadFile(filePath);
// 指定上传并发线程数,默认值为1。
uploadFileRequest.setTaskNum(5);
// 指定上传的分片大小,单位为字节,取值范围为100 KB~5 GB。默认值为100 KB。
uploadFileRequest.setPartSize(1 * 1024 * 1024);
// 开启断点续传,默认关闭。
uploadFileRequest.setEnableCheckpoint(true);
// 记录本地分片上传结果的文件。上传过程中的进度信息会保存在该文件中,如果某一分片上传失败,再次上传时会根据文件中记录的点继续上传。上传完成后,该文件会被删除。
// 如果未设置该值,默认与待上传的本地文件同路径,名称为${uploadFile}.ucp。
uploadFileRequest.setCheckpointFile("yourCheckpointFile");
// 文件的元数据。
uploadFileRequest.setObjectMetadata(metadata);
// 配置上传回调参数
Callback callback = new Callback();
callback.setCallbackUrl(callbackUrl);
//(可选)设置回调请求消息头中Host的值,即您的服务器配置Host的值。
// callback.setCallbackHost("yourCallbackHost");
// 设置回调请求的 Body 内容,采用 JSON 格式,并在其中定义占位符变量。
callback.setCalbackBodyType(Callback.CalbackBodyType.JSON);
callback.setCallbackBody("{\\\"bucket\\\":${bucket},\\\"object\\\":${object},\\\"mimeType\\\":${mimeType},\\\"size\\\":${size},\\\"my_var1\\\":${x:var1},\\\"my_var2\\\":${x:var2}}");
// 设置发起回调请求的自定义参数,由Key和Value组成,Key必须以x:开始。
callback.addCallbackVar("x:var1", "value1");
callback.addCallbackVar("x:var2", "value2");
// 设置上传回调,参数为Callback类型。
uploadFileRequest.setCallback(callback);
// 断点续传上传。
ossClient.uploadFile(uploadFileRequest);
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (Throwable ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
// 关闭OSSClient。
if (ossClient != null) {
ossClient.shutdown();
}
}
}
}
使用预签名URL上传文件并设置回调
文件拥有者生成指定上传回调参数的PUT方法的预签名URL。
import com.aliyun.oss.*; import com.aliyun.oss.common.auth.CredentialsProviderFactory; import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider; import com.aliyun.oss.common.comm.SignVersion; import com.aliyun.oss.internal.OSSHeaders; import com.aliyun.oss.model.GeneratePresignedUrlRequest; import java.net.URL; import java.text.SimpleDateFormat; import java.util.*; public class OssPresignExample { public static void main(String[] args) throws Throwable { // 以华东1(杭州)的外网Endpoint为例,其它Region请按实际情况填写。 String endpoint = "https://oss-cn-hangzhou.aliyuncs.com"; // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider(); // 填写Bucket名称,例如examplebucket。 String bucketName = "examplebucket"; // 填写Object完整路径,例如exampleobject.txt。Object完整路径中不能包含Bucket名称。 String objectName = "exampleobject.txt"; // 填写Bucket所在地域。以华东1(杭州)为例,Region填写为cn-hangzhou。 String region = "cn-hangzhou"; // 创建OSSClient实例。 // 当OSSClient实例不再使用时,调用shutdown方法以释放资源。 ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration(); clientBuilderConfiguration.setSignatureVersion(SignVersion.V4); OSS ossClient = OSSClientBuilder.create() .endpoint(endpoint) .credentialsProvider(credentialsProvider) .clientConfiguration(clientBuilderConfiguration) .region(region) .build(); URL signedUrl = null; try { // 构造回调参数 String callbackUrl = "http://www.example.com/callback"; String callbackBody = "{\"callbackUrl\":\"" + callbackUrl + "\",\"callbackBody\":\"bucket=${bucket}&object=${object}&my_var_1=${x:var1}&my_var_2=${x:var2}\"}"; String callbackBase64 = Base64.getEncoder().encodeToString(callbackBody.getBytes()); String callbackVarJson = "{\"x:var1\":\"value1\",\"x:var2\":\"value2\"}"; String callbackVarBase64 = Base64.getEncoder().encodeToString(callbackVarJson.getBytes()); // 设置请求头。 Map<String, String> headers = new HashMap<String, String>(); // 指定CALLBACK。 headers.put(OSSHeaders.OSS_HEADER_CALLBACK, callbackBase64); // 指定CALLBACK-VAR。 headers.put(OSSHeaders.OSS_HEADER_CALLBACK_VAR, callbackVarBase64); // 设置过期时间(3600秒后) Date expiration = new Date(new Date().getTime() + 3600 * 1000); // 格式化过期时间 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); String expirationStr = dateFormat.format(expiration); // 构造请求 GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName); request.setMethod(HttpMethod.PUT); request.setExpiration(expiration); // 将请求头加入到request中。 request.setHeaders(headers); //打印callback参数和callback-var参数 System.out.println("callback:"+callbackBase64); System.out.println("callback-var:"+callbackVarBase64); // 生成预签名URL URL url = ossClient.generatePresignedUrl(request); // 输出结果 System.out.println("method: PUT,"); System.out.println(" expiration: " + expirationStr + ","); System.out.println(" url: " + url); } catch (OSSException oe) { System.out.println("Caught an OSSException, which means your request made it to OSS, " + "but was rejected with an error response for some reason."); System.out.println("Error Message:" + oe.getErrorMessage()); System.out.println("Error Code:" + oe.getErrorCode()); System.out.println("Request ID:" + oe.getRequestId()); System.out.println("Host ID:" + oe.getHostId()); } catch (ClientException ce) { System.out.println("Caught an ClientException, which means the client encountered " + "a serious internal problem while trying to communicate with OSS, " + "such as not being able to access the network."); System.out.println("Error Message:" + ce.getMessage()); } } }
其他人使用PUT方法的预签名URL上传文件。
curl
curl -X PUT \ -H "x-oss-callback: eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9" \ -H "x-oss-callback-var: eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==" \ -T "C:\\Users\\demo.txt" \ "https://exampleobject.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T083238Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************%2F20241112%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-signature=ed5a******************************************************"
Python
import requests def upload_file(signed_url, file_path, headers=None): """ 使用预签名的URL上传文件到OSS。 :param signed_url: 预签名的URL。 :param file_path: 要上传的文件的完整路径。 :param headers: 可选,自定义HTTP头部。 :return: None """ if not headers: headers = {} try: with open(file_path, 'rb') as file: response = requests.put(signed_url, data=file, headers=headers) print(f"返回上传状态码:{response.status_code}") if response.status_code == 200: print("使用网络库上传成功") else: print("上传失败") print(response.text) except Exception as e: print(f"发生错误:{e}") if __name__ == "__main__": # 将<signedUrl>替换为授权URL。 signed_url = "<signedUrl>" # 填写本地文件的完整路径。如果未指定本地路径,则默认从脚本所在目录中上传文件。 file_path = "C:\\Users\\demo.txt" headers = { "x-oss-callback": "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9", "x-oss-callback-var": "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==", } upload_file(signed_url, file_path, headers)
Go
package main import ( "bytes" "fmt" "io" "net/http" "os" ) func uploadFile(signedUrl string, filePath string, headers map[string]string) error { // 打开文件 file, err := os.Open(filePath) if err != nil { return err } defer file.Close() // 读取文件内容 fileBytes, err := io.ReadAll(file) if err != nil { return err } // 创建请求 req, err := http.NewRequest("PUT", signedUrl, bytes.NewBuffer(fileBytes)) if err != nil { return err } // 设置请求头 for key, value := range headers { req.Header.Add(key, value) } // 发送请求 client := &http.Client{} resp, err := client.Do(req) if err != nil { return err } defer resp.Body.Close() // 处理响应 fmt.Printf("返回上传状态码:%d\n", resp.StatusCode) if resp.StatusCode == 200 { fmt.Println("使用网络库上传成功") } else { fmt.Println("上传失败") } body, _ := io.ReadAll(resp.Body) fmt.Println(string(body)) return nil } func main() { // 将<signedUrl>替换为授权URL。 signedUrl := "<signedUrl>" // 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。 filePath := "C:\\Users\\demo.txt" // 设置请求头,这里的请求头信息需要与生成URL时的信息一致。 headers := map[string]string{ "x-oss-callback": "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9", "x-oss-callback-var": "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==", } err := uploadFile(signedUrl, filePath, headers) if err != nil { fmt.Printf("发生错误:%v\n", err) } }
Java
import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPut; import org.apache.http.entity.FileEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import java.io.*; import java.net.URL; import java.util.*; public class SignUrlUpload { public static void main(String[] args) throws Throwable { CloseableHttpClient httpClient = null; CloseableHttpResponse response = null; // 将<signedUrl>替换为授权URL。 URL signedUrl = new URL("<signedUrl>"); // 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。 String pathName = "C:\\Users\\demo.txt"; // 设置请求头,包括x-oss-callback和x-oss-callback-var。 Map<String, String> headers = new HashMap<String, String>(); headers.put("x-oss-callback", "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9"); headers.put("x-oss-callback-var", "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ=="); try { HttpPut put = new HttpPut(signedUrl.toString()); System.out.println(put); HttpEntity entity = new FileEntity(new File(pathName)); put.setEntity(entity); // 如果生成预签名URL时设置了header参数,则调用预签名URL上传文件时,也需要将这些参数发送至服务端。如果签名和发送至服务端的不一致,会报签名错误。 for(Map.Entry header: headers.entrySet()){ put.addHeader(header.getKey().toString(),header.getValue().toString()); } httpClient = HttpClients.createDefault(); response = httpClient.execute(put); System.out.println("返回上传状态码:"+response.getStatusLine().getStatusCode()); if(response.getStatusLine().getStatusCode() == 200){ System.out.println("使用网络库上传成功"); } System.out.println(response.toString()); } catch (Exception e){ e.printStackTrace(); } finally { response.close(); httpClient.close(); } } }
PHP
<?php function uploadFile($signedUrl, $filePath, $headers = []) { // 检查文件是否存在 if (!file_exists($filePath)) { echo "文件不存在: $filePath\n"; return; } // 初始化cURL会话 $ch = curl_init(); // 设置cURL选项 curl_setopt($ch, CURLOPT_URL, $signedUrl); curl_setopt($ch, CURLOPT_PUT, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_INFILE, fopen($filePath, 'rb')); curl_setopt($ch, CURLOPT_INFILESIZE, filesize($filePath)); curl_setopt($ch, CURLOPT_HTTPHEADER, array_map(function($key, $value) { return "$key: $value"; }, array_keys($headers), $headers)); // 执行cURL请求 $response = curl_exec($ch); // 获取HTTP状态码 $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); // 关闭cURL会话 curl_close($ch); // 输出结果 echo "返回上传状态码:$httpCode\n"; if ($httpCode == 200) { echo "使用网络库上传成功\n"; } else { echo "上传失败\n"; } echo $response . "\n"; } // 将<signedUrl>替换为授权URL。 $signedUrl = "<signedUrl>"; // 填写本地文件的完整路径。如果未指定本地路径,则默认从脚本所在目录中上传文件。 $filePath = "C:\\Users\\demo.txt"; $headers = [ "x-oss-callback" => "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9", "x-oss-callback-var" => "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==", ]; uploadFile($signedUrl, $filePath, $headers); ?>