Os callbacks de upload permitem acionar a lógica de negócios no servidor após o upload de um objeto, sem necessidade de polling. Ao anexar parâmetros de callback a uma solicitação de upload, o OSS envia uma requisição HTTP POST para o seu servidor de callback assim que o upload é concluído, aguarda a resposta do servidor e retorna o resultado do upload ao cliente.
Observações de uso
Os exemplos neste tópico usam o endpoint público da região China (Hangzhou) (
https://oss-cn-hangzhou.aliyuncs.com). Para acessar o OSS a partir de outros serviços da Alibaba Cloud na mesma região, use o endpoint interno correspondente. Para ver as regiões e endpoints compatíveis, consulte Regiões e endpoints do OSS.As credenciais de acesso nestes exemplos são lidas de variáveis de ambiente (
OSS_ACCESS_KEY_IDeOSS_ACCESS_KEY_SECRET). Para obter detalhes sobre a configuração, consulte Configurar credenciais de acesso.Estes exemplos criam uma instância OSSClient usando um endpoint do OSS. Para criar uma instância com um nome de domínio personalizado ou Security Token Service (STS), consulte Exemplos de configuração para cenários comuns.
Como funciona
Todos os exemplos neste tópico compartilham o mesmo padrão de configuração de callback:
Crie um objeto
Callbacke defina a URL de callback e o corpo da requisição.Adicione parâmetros personalizados opcionais com o prefixo
x:.Anexe o objeto
Callbackà solicitação de upload.Após o OSS armazenar o objeto com sucesso, ele envia uma requisição HTTP POST para sua URL de callback com o corpo resolvido.
Leia a resposta do servidor de callback no resultado do upload.
O corpo do callback usa variáveis de espaço reservado (por exemplo, ${bucket}, ${object}, ${size}) que o OSS substitui por valores reais antes de enviar a requisição. Variáveis personalizadas usam a sintaxe ${x:varname}.
Exemplo de corpo de callback (modelo):
{"bucket":${bucket},"object":${object},"mimeType":${mimeType},"size":${size},"my_var1":${x:var1},"my_var2":${x:var2}}
Exemplo de corpo resolvido enviado ao seu servidor:
{"bucket":"examplebucket","object":"exampledir/exampleobject.txt","mimeType":"text/plain","size":"9","my_var1":"value1","my_var2":"value2"}
Código de exemplo
Configure upload callbacks for simple upload
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{
// Specify the endpoint of the region. In this example, the endpoint of the China (Hangzhou) region is used.
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured.
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// Specify the name of the bucket. Example: examplebucket.
String bucketName = "examplebucket";
// Specify the full path of the object. Example: exampledir/exampleobject.txt. Do not include the bucket name in the full path.
String objectName = "exampledir/exampleobject.txt";
// Specify the address of the server to which the callback request is sent. Example: https://example.com:23450.
String callbackUrl = "yourCallbackServerUrl";
// Specify the region in which the bucket is located. Example: cn-hangzhou.
String region = "cn-hangzhou";
// Create an OSSClient instance.
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()));
// Configure upload callback parameters.
Callback callback = new Callback();
callback.setCallbackUrl(callbackUrl);
// (Optional) Specify the Host header in the callback request.
// callback.setCallbackHost("yourCallbackHost");
// Set the callback request body in JSON format and define placeholder variables.
callback.setCalbackBodyType(Callback.CalbackBodyType.JSON);
callback.setCallbackBody("{\\\"bucket\\\":${bucket},\\\"object\\\":${object},\\\"mimeType\\\":${mimeType},\\\"size\\\":${size},\\\"my_var1\\\":${x:var1},\\\"my_var2\\\":${x:var2}}");
// Add custom parameters. Each key must start with x:.
callback.addCallbackVar("x:var1", "value1");
callback.addCallbackVar("x:var2", "value2");
putObjectRequest.setCallback(callback);
// Upload the object.
PutObjectResult putObjectResult = ossClient.putObject(putObjectRequest);
// Read the callback server's response.
byte[] buffer = new byte[1024];
putObjectResult.getResponse().getContent().read(buffer);
// Close the stream after reading to prevent connection leaks.
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();
}
}
}
}
Configure upload callbacks for multipart upload
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 {
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
String bucketName = "examplebucket";
String objectName = "exampledir/exampleobject.txt";
String filePath = "D:\\localpath\\examplefile.txt";
String region = "cn-hangzhou";
// Specify the address of the server to which the callback request is sent. Example: https://example.com:23450.
String callbackUrl = "https://example.com:23450";
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
try {
// Initialize the multipart upload task.
InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, objectName);
// Set the Content-Type from the file.
ObjectMetadata metadata = new ObjectMetadata();
if (metadata.getContentType() == null) {
metadata.setContentType(Mimetypes.getInstance().getMimetype(new File(filePath), objectName));
}
System.out.println("Content-Type: " + metadata.getContentType());
request.setObjectMetadata(metadata);
InitiateMultipartUploadResult upresult = ossClient.initiateMultipartUpload(request);
String uploadId = upresult.getUploadId();
// partETags stores the PartETag for each uploaded part.
List<PartETag> partETags = new ArrayList<PartETag>();
// Each part can be 100 KB to 5 GB. The last part can be smaller than 100 KB.
// In this example, the part size is set to 1 MB.
final long partSize = 1 * 1024 * 1024L;
final File sampleFile = new File(filePath);
long fileLength = sampleFile.length();
int partCount = (int) (fileLength / partSize);
if (fileLength % partSize != 0) {
partCount++;
}
// Upload each part.
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);
InputStream instream = new FileInputStream(sampleFile);
instream.skip(startPos);
uploadPartRequest.setInputStream(instream);
uploadPartRequest.setPartSize(curPartSize);
// Part numbers range from 1 to 10,000. An InvalidArgument error is returned for numbers outside this range.
uploadPartRequest.setPartNumber(i + 1);
// Parts can be uploaded in any order and from different OSS clients. OSS sorts them by part number before combining.
UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
partETags.add(uploadPartResult.getPartETag());
instream.close();
}
// Complete the multipart upload and attach the callback.
// OSS verifies all PartETags before combining parts into the final object.
CompleteMultipartUploadRequest completeMultipartUploadRequest =
new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags);
// Configure upload callback parameters.
Callback callback = new Callback();
callback.setCallbackUrl(callbackUrl);
// (Optional) Specify the Host header in the callback request.
// callback.setCallbackHost("yourCallbackHost");
callback.setCalbackBodyType(Callback.CalbackBodyType.JSON);
callback.setCallbackBody("{\\\"bucket\\\":${bucket},\\\"object\\\":${object},\\\"mimeType\\\":${mimeType},\\\"size\\\":${size},\\\"my_var1\\\":${x:var1},\\\"my_var2\\\":${x:var2}}");
callback.addCallbackVar("x:var1", "value1");
callback.addCallbackVar("x:var2", "value2");
completeMultipartUploadRequest.setCallback(callback);
CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest);
System.out.println("Upload successful, 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();
}
}
}
}
Configure upload callbacks for form upload
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 {
// Specify the full path of the local file to upload.
private static final String localFilePath = "D:\\localpath\\examplefile.txt";
// In this example, the endpoint of the China (Hangzhou) region is used.
private static final String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// Obtain access credentials from environment variables.
private static final String accessKeyId = System.getenv("OSS_ACCESS_KEY_ID");
private static final String accessKeySecret = System.getenv("OSS_ACCESS_KEY_SECRET");
private static final String bucketName = "examplebucket";
private static final String objectName = "exampledir/exampleobject.txt";
// Specify the URL of the server to receive callback requests. Example: http://oss-demo.oss-cn-hangzhou.aliyuncs.com:23450.
private static final String callbackServerUrl = "http://oss-demo.oss-cn-hangzhou.aliyuncs.com:23450";
// Specify the Host header in the callback request. Example: oss-cn-hangzhou.aliyuncs.com.
private static final String callbackServerHost = "";
private static final String region = "cn-hangzhou";
private static Date requestDateTime = new Date();
/**
* Perform form upload.
*/
private void PostObject() throws Exception {
// Construct the upload 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);
// Configure callback parameters.
Callback callback = new Callback();
callback.setCallbackUrl(callbackServerUrl);
callback.setCallbackHost(callbackServerHost);
callback.setCalbackBodyType(Callback.CalbackBodyType.JSON);
callback.setCallbackBody("{\\\"bucket\\\":${bucket},\\\"object\\\":${object},\\\"mimeType\\\":${mimeType},\\\"size\\\":${size},\\\"my_var1\\\":${x:var1},\\\"my_var2\\\":${x:var2}}");
// Custom parameter keys must start with x: and be lowercase.
callback.addCallbackVar("x:var1", "value1");
callback.addCallbackVar("x:var2", "value2");
setCallBack(formFields, callback);
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()));
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());
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));
return signature.computeHash(signingService, "aliyun_v4_request".getBytes(StringUtils.UTF8));
}
public static void main(String[] args) throws Exception {
PostObjectCallbackV4Demo ossPostObject = new PostObjectCallbackV4Demo();
ossPostObject.PostObject();
}
}
Configure upload callbacks for resumable upload
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 {
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
String bucketName = "examplebucket";
String objectName = "exampledir/exampleobject.txt";
String filePath = "D:\\localpath\\examplefile.txt";
String region = "cn-hangzhou";
// Specify the address of the server to which the callback request is sent. Example: https://example.com:23450.
String callbackUrl = "http://example.com:23450/callback";
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
try {
// Set the Content-Type from the file.
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 uploadFileRequest = new UploadFileRequest(bucketName, objectName);
uploadFileRequest.setUploadFile(filePath);
// Number of concurrent upload threads. Default: 1.
uploadFileRequest.setTaskNum(5);
// Part size in bytes. Valid values: 100 KB to 5 GB. Default: 100 KB.
uploadFileRequest.setPartSize(1 * 1024 * 1024);
// Enable resumable upload. Disabled by default.
uploadFileRequest.setEnableCheckpoint(true);
// Path to the checkpoint file that tracks upload progress.
// If a part fails, the upload resumes from where it left off.
// The checkpoint file is deleted automatically after the upload completes.
// Default path: ${uploadFile}.ucp (same directory as the file being uploaded).
uploadFileRequest.setCheckpointFile("yourCheckpointFile");
uploadFileRequest.setObjectMetadata(metadata);
// Configure upload callback parameters.
Callback callback = new Callback();
callback.setCallbackUrl(callbackUrl);
// (Optional) Specify the Host header in the callback request.
// callback.setCallbackHost("yourCallbackHost");
callback.setCalbackBodyType(Callback.CalbackBodyType.JSON);
callback.setCallbackBody("{\\\"bucket\\\":${bucket},\\\"object\\\":${object},\\\"mimeType\\\":${mimeType},\\\"size\\\":${size},\\\"my_var1\\\":${x:var1},\\\"my_var2\\\":${x:var2}}");
callback.addCallbackVar("x:var1", "value1");
callback.addCallbackVar("x:var2", "value2");
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 {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
}
Use a presigned URL to upload an object with callbacks
Inclua parâmetros de callback na URL pré-assinada para permitir que os clientes façam upload de objetos com callbacks usando requisições HTTP PUT, sem precisar de credenciais de acesso no momento do upload.
Etapa 1: Gerar uma URL pré-assinada com parâmetros de callback
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 {
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
String bucketName = "examplebucket";
String objectName = "exampleobject.txt";
String region = "cn-hangzhou";
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 {
// Build the callback parameter as a Base64-encoded JSON string.
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());
// Build the callback variable parameter as a Base64-encoded JSON string.
String callbackVarJson = "{\"x:var1\":\"value1\",\"x:var2\":\"value2\"}";
String callbackVarBase64 = Base64.getEncoder().encodeToString(callbackVarJson.getBytes());
// Add callback parameters to the request headers.
Map<String, String> headers = new HashMap<String, String>();
headers.put(OSSHeaders.OSS_HEADER_CALLBACK, callbackBase64);
headers.put(OSSHeaders.OSS_HEADER_CALLBACK_VAR, callbackVarBase64);
// Set the URL validity period to 3600 seconds.
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.setHeaders(headers);
System.out.println("callback:" + callbackBase64);
System.out.println("callback-var:" + callbackVarBase64);
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());
}
}
}
Etapa 2: Fazer upload usando a URL pré-assinada
Use a URL pré-assinada para fazer upload de um objeto. Passe os cabeçalhos x-oss-callback e x-oss-callback-var com os mesmos valores codificados em Base64 usados ao gerar a 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):
"""
Upload a file to OSS using a presigned URL.
:param signed_url: The presigned URL.
:param file_path: The full path of the file to upload.
:param headers: Optional. Custom HTTP headers.
: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"Upload status code returned: {response.status_code}")
if response.status_code == 200:
print("Upload successful using the network library.")
else:
print("Upload failed.")
print(response.text)
except Exception as e:
print(f"An error occurred: {e}")
if __name__ == "__main__":
# Replace <signedUrl> with the authorized URL.
signed_url = "<signedUrl>"
# Enter the full path of the local file. If you do not specify a local path, the file is uploaded from the directory where the script is located by default.
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 {
// Open the file.
file, err := os.Open(filePath)
if err != nil {
return err
}
defer file.Close()
// Read the file content.
fileBytes, err := io.ReadAll(file)
if err != nil {
return err
}
// Create a request.
req, err := http.NewRequest("PUT", signedUrl, bytes.NewBuffer(fileBytes))
if err != nil {
return err
}
// Set request headers.
for key, value := range headers {
req.Header.Add(key, value)
}
// Send the request.
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
// Process the response.
fmt.Printf("Upload status code returned: %d\n", resp.StatusCode)
if resp.StatusCode == 200 {
fmt.Println("Upload successful using the network library.")
} else {
fmt.Println("Upload failed.")
}
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
return nil
}
func main() {
// Replace <signedUrl> with the authorized URL.
signedUrl := "<signedUrl>"
// Enter the full path of the local file. If you do not specify a local path, the file is uploaded from the project's corresponding local path by default.
filePath := "C:\\Users\\demo.txt"
// Set request headers. The header information here must be consistent with the information used to generate the URL.
headers := map[string]string{
"x-oss-callback": "eyJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9XHUwMDI2b2JqZWN0PSR7b2JqZWN0fVx1MDAyNnNpemU9JHtzaXplfVx1MDAyNm15X3Zhcl8xPSR7eDpteV92YXIxfVx1MDAyNm15X3Zhcl8yPSR7eDpteV92YXIyfSIsImNhbGxiYWNrQm9keVR5cGUiOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQiLCJjYWxsYmFja1VybCI6Imh0dHA6Ly9leGFtcGxlLmNvbToyMzQ1MCJ9",
"x-oss-callback-var": "eyJ4Om15X3ZhcjEiOiJ0aGkgaXMgdmFyIDEiLCJ4Om15X3ZhcjIiOiJ0aGkgaXMgdmFyIDIifQ==",
}
err := uploadFile(signedUrl, filePath, headers)
if err != nil {
fmt.Printf("An error occurred: %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 IOException {
CloseableHttpClient httpClient = null;
CloseableHttpResponse response = null;
// Replace <signedUrl> with the authorized URL.
URL signedUrl = new URL("<signedUrl>");
// Enter the full path of the local file. If you do not specify a local path, the file is uploaded from the project's corresponding local path by default.
String pathName = "C:\\Users\\demo.txt";
// Set request headers, including x-oss-callback and 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);
// If header parameters were set when generating the presigned URL, these parameters must also be sent to the server when using the presigned URL to upload the file. If the signature and the parameters sent to the server do not match, a signature error will occur.
for(Map.Entry<String, String> header: headers.entrySet()){
put.addHeader(header.getKey(),header.getValue());
}
httpClient = HttpClients.createDefault();
response = httpClient.execute(put);
System.out.println("Upload status code returned:"+response.getStatusLine().getStatusCode());
if(response.getStatusLine().getStatusCode() == 200){
System.out.println("Upload successful using the network library.");
}
System.out.println(response.toString());
} catch (Exception e){
e.printStackTrace();
} finally {
if (response != null) {
response.close();
}
if (httpClient != null) {
httpClient.close();
}
}
}
}
PHP
<?php
function uploadFile($signedUrl, $filePath, $headers = []) {
// Check if the file exists.
if (!file_exists($filePath)) {
echo "File does not exist: $filePath\n";
return;
}
// Initialize cURL session.
$ch = curl_init();
// Set cURL options.
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));
// Execute cURL request.
$response = curl_exec($ch);
// Get HTTP status code.
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
// Close cURL session.
curl_close($ch);
// Output the result.
echo "Upload status code returned: $httpCode\n";
if ($httpCode == 200) {
echo "Upload successful using the network library.\n";
} else {
echo "Upload failed.\n";
}
echo $response . "\n";
}
// Replace <signedUrl> with the authorized URL.
$signedUrl = "<signedUrl>";
// Enter the full path of the local file. If you do not specify a local path, the file is uploaded from the directory where the script is located by default.
$filePath = "C:\\Users\\demo.txt";
$headers = [
"x-oss-callback" => "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9",
"x-oss-callback-var" => "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==",
];
uploadFile($signedUrl, $filePath, $headers);
?>
Solução de problemas
Vazamentos de conexão após leitura da resposta de callback
Após ler a resposta do servidor de callback em putObjectResult.getResponse().getContent(), sempre feche o stream. Deixar o stream aberto impede que a conexão HTTP subjacente retorne ao pool, o que eventualmente esgota as conexões disponíveis.
putObjectResult.getResponse().getContent().read(buffer);
putObjectResult.getResponse().getContent().close(); // Required
Servidor de callback inacessível
A URL de callback deve ser acessível pelo serviço OSS, não apenas pela sua máquina local. Se o OSS não conseguir alcançar a URL de callback, o upload falhará com um erro relacionado ao callback.
Verifique se:
O servidor de callback está acessível publicamente ou alcançável pela rede do OSS.
A URL de callback usa o protocolo correto (
http://ouhttps://) e porta.Nenhuma regra de firewall bloqueia requisições de entrada provenientes dos intervalos de IP do OSS.
Incompatibilidade de assinatura em URL pré-assinada
Ao usar URLs pré-assinadas, os valores dos cabeçalhos x-oss-callback e x-oss-callback-var enviados durante o upload devem corresponder exatamente àqueles incluídos na assinatura quando a URL foi gerada. Qualquer diferença causa um erro de verificação de assinatura.