OSS在完成檔案(Object)上傳時可以提供回調(Callback)給應用伺服器。您只需要在發送給OSS的請求中攜帶相應的Callback參數,即可實現上傳回調。
注意事項
本文以華東1(杭州)外網Endpoint為例。如果您希望通過與OSS同地區的其他阿里雲產品訪問OSS,請使用內網Endpoint。關於OSS支援的Region與Endpoint的對應關係,請參見地區和Endpoint。
本文以從環境變數讀取存取憑證為例。如何配置訪問憑證,請參見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); ?>