By default, the access control list (ACL) of an Object Storage Service (OSS) object in a bucket is private. Only the object owner has the permissions to upload an object to the bucket. You can use OSS SDK for Java to generate a presigned URL, which you can then share with a user to allow them to upload an object to the bucket. When you generate the presigned URL, you can specify its validity period to limit the time during which the user can upload the object. During the validity period of the presigned URL, the user can use the URL to upload an object to the bucket multiple times. Uploading the object multiple times may cause data overwriting. After the validity period of the presigned URL ends, the user can no longer use the presigned URL to upload an object. To prolong access for the user, you can regenerate a presinged URL.
Usage notes
In this topic, the public endpoint of the China (Hangzhou) region is used. To access OSS from other Alibaba Cloud services in the same region, use an internal endpoint. For details about supported regions and endpoints, see Regions and endpoints.
In this topic, access credentials are obtained from environment variables. For more information about how to configure access credentials, see Configure access credentials.
In this topic, an OSSClient instance is created by using an OSS endpoint. If you want to create an OSSClient instance by using custom domain names or Security Token Service (STS), see Configuration examples for common scenarios.
You do not need specific permissions to generate a presigned URL. However, to allow others to use the presigned URL for uploading an object, you must have the
oss:PutObject
permission. For more information, see Authorize a RAM user to access multiple directories in a bucket.In this topic, the signature algorithm V4 is used to generate presigned URLs with a validity period of up to 7 days. For more information, see (Recommended) Include a V4 signature in a URL.
Process
The following figure shows how to use a presigned URL that allows HTTP PUT requests to upload an object to OSS.
Sample code
Generate a presigned URL that allows data uploads by using the HTTP PUT method:
import com.aliyun.oss.*; import com.aliyun.oss.common.auth.*; import com.aliyun.oss.common.comm.SignVersion; import com.aliyun.oss.model.GeneratePresignedUrlRequest; import java.net.URL; import java.util.*; import java.util.Date; public class GetSignUrl { public static void main(String[] args) throws Throwable { // In this example, the endpoint of the China (Hangzhou) region is used. Specify your actual endpoint. 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: exampleobject.txt. Do not include the bucket name in the full path of the object. String objectName = "exampleobject.txt"; // Specify the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the region to cn-hangzhou. String region = "cn-hangzhou"; // Create an OSSClient instance. // Call the shutdown method to release resources when the OSSClient is no longer in use. 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 { // Specify the validity period of the presigned URL. Unit: milliseconds. In this example, the validity period is set to 1 hour. Date expiration = new Date(new Date().getTime() + 3600 * 1000L); // Generate a presigned URL. GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.PUT); // Specify the validity period of the presigned URL. request.setExpiration(expiration); // Generate a presigned URL that allows HTTP PUT requests. signedUrl = ossClient.generatePresignedUrl(request); // Display the presigned URL. System.out.println("signed url for putObject: " + signedUrl); } 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()); } } }
Upload a file by using the presigned URL:
curl
curl -X PUT -T /path/to/local/file "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******************************************************"
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; // Replace <signedUrl> with the presigned URL. URL signedUrl = new URL("<signedUrl>"); // Specify the full path of the local file that you want to upload. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. String pathName = "C:\\Users\\demo.txt"; try { HttpPut put = new HttpPut(signedUrl.toString()); System.out.println(put); HttpEntity entity = new FileEntity(new File(pathName)); put.setEntity(entity); httpClient = HttpClients.createDefault(); response = httpClient.execute(put); System.out.println("Status code:"+response.getStatusLine().getStatusCode()); if(response.getStatusLine().getStatusCode() == 200){ System.out.println("The object is uploaded by using the library."); } System.out.println(response.toString()); } catch (Exception e){ e.printStackTrace(); } finally { response.close(); httpClient.close(); } } }
Go
package main import ( "fmt" "io" "net/http" "os" ) func uploadFile(signedUrl, filePath string) error { // Open the local file. file, err := os.Open(filePath) if err != nil { return fmt.Errorf("Unable to open the local file: %w", err) } defer file.Close() // Create an HTTP client. client := &http.Client{} // Create a PUT request. req, err := http.NewRequest("PUT", signedUrl, file) if err != nil { return fmt.Errorf("Failed to create the request: %w", err) } // Send the request. resp, err := client.Do(req) if err != nil { return fmt.Errorf("Failed to send the request:: %w", err) } defer resp.Body.Close() // Read the response. body, err := io.ReadAll(resp.Body) if err != nil { return fmt.Errorf("Failed to read the request: %w", err) } fmt.Printf("Status code: %d\n", resp.StatusCode) if resp.StatusCode == 200 { fmt.Println("The object is uploaded by using the library.") } fmt.Println(string(body)) return nil } func main() { // Replace <signedUrl> with the presigned URL. signedUrl := "<signedUrl>" // Specify the full path of the local file that you want to upload. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. filePath := "C:\\Users\\demo.txt" err := uploadFile(signedUrl, filePath) if err != nil { fmt.Println("An error occurred: ", err) } }
python
import requests def upload_file(signed_url, file_path): try: # Open the local file that you want to upload. with open(file_path, 'rb') as file: # Send a PUT request to upload the local file. response = requests.put(signed_url, data=file) print(f"Status code: {response.status_code}") if response.status_code == 200: print("The object is uploaded by using the library.") print(response.text) except Exception as e: print(f"An error occurred: {e}") if __name__ == "__main__": # Replace <signedUrl> with the generated signed URL. signed_url = "<signedUrl>" # Specify the full path of the local file. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. file_path = "C:\\Users\\demo.txt" upload_file(signed_url, file_path)
Node.js
const fs = require('fs'); const axios = require('axios'); async function uploadFile(signedUrl, filePath) { try { // Create a read stream. const fileStream = fs.createReadStream(filePath); // Send a PUT request to upload the local file. const response = await axios.put(signedUrl, fileStream, { headers: { 'Content-Type': 'application/octet-stream' // Specify the Content-Type parameter. } }); console.log(`Status code: ${response.status}`); if (response.status === 200) { console.log("The object is uploaded by using the library."); } console.log(response.data); } catch (error) { console.error(`An error occurred: ${error.message}`); } } // Specify the main function. (async () => { // Replace <signedUrl> with the presigned URL. const signedUrl = '<signedUrl>'; // Specify the full path of the local file that you want to upload. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. const filePath = 'C:\\Users\\demo.txt'; await uploadFile(signedUrl, filePath); })();
browser.js
ImportantWhen uploading an object using Browser.js and a presigned URL, a 403 SignatureNotMatch error that indicates signature inconsistency may occur. This is typically caused by the browser's automatic inclusion of the Content-Type request header, which that was not specified when the presigned URL was generated. To prevent this error, ensure that the Content-Type header is specified when generating a presigned URL.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>File Upload Example</title> </head> <body> <h1>File Upload Example</h1> <! -- Select File --> <input type="file" id="fileInput" /> <button id="uploadButton">Upload File</button> <script> // Replace <signedUrl> with the presigned URL that was generated in Step 1. const signedUrl = "<signedUrl>"; document.getElementById('uploadButton').addEventListener('click', async () => { const fileInput = document.getElementById('fileInput'); const file = fileInput.files[0]; if (!file) { alert('Please select a file to upload.'); return; } try { await upload(file, signedUrl); alert('File uploaded successfully!'); } catch (error) { console.error('Error during upload:', error); alert('Upload failed: ' + error.message); } }); /** * Upload a file to OSS. * @param {File} file - The file to be uploaded. * @param {string} presignedUrl - The presigned URL. */ const upload = async (file, presignedUrl) => { const response = await fetch(presignedUrl, { method: 'PUT', body: file, // Upload the entire file. }); if (!response.ok) { throw new Error(`Upload failed, status: ${response.status}`); } console.log('File uploaded successfully'); }; </script> </body> </html>
C#
using System.Net.Http.Headers; // Specify the full path of the local file that you want to upload. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. var filePath = "C:\\Users\\demo.txt"; // Replace <signedUrl> with the presigned URL. var presignedUrl = "<signedUrl>"; // Create an HTTP client and a local file stream. using var httpClient = new HttpClient(); using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read); using var content = new StreamContent(fileStream); // Create a PUT request. var request = new HttpRequestMessage(HttpMethod.Put, presignedUrl); request.Content = content; // Send a request. var response = await httpClient.SendAsync(request); // Process the response. if (response.IsSuccessStatusCode) { Console.WriteLine($"Uploaded! Status Code: {response.StatusCode}"); Console.WriteLine("Response Header:"); foreach (var header in response.Headers) { Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}"); } } else { string responseContent = await response.Content.ReadAsStringAsync(); Console.WriteLine($"Upload Failed! Status Code: {response.StatusCode}"); Console.WriteLine("Response content: " + responseContent); }
C++
#include <iostream> #include <fstream> #include <curl/curl.h> void uploadFile(const std::string& signedUrl, const std::string& filePath) { CURL *curl; CURLcode res; curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if (curl) { // Specify the presigned URL. curl_easy_setopt(curl, CURLOPT_URL, signedUrl.c_str()); // Set the request method to PUT. curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); // Open the local file. FILE *file = fopen(filePath.c_str(), "rb"); if (!file) { std::cerr << "Unable to open the file: " << filePath << std::endl; return; } // Query the size of the local file. fseek(file, 0, SEEK_END); long fileSize = ftell(file); fseek(file, 0, SEEK_SET); // Specify the size of the local file. curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fileSize); // Specify the input file handle. curl_easy_setopt(curl, CURLOPT_READDATA, file); // Execute the request. res = curl_easy_perform(curl); if (res != CURLE_OK) { std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl; } else { long httpCode = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode); std::cout << "Status code: " << httpCode << std::endl; if (httpCode == 200) { std::cout << "The object is uploaded by using the network library." << std::endl; } } // Close the local file. fclose(file); // Clear the cURL handle. curl_easy_cleanup(curl); } curl_global_cleanup(); } int main() { // Replace <signedUrl> with the presigned URL. std::string signedUrl = "<signedUrl>"; // Specify the full path of the local file that you want to upload. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. std::string filePath = "C:\\Users\\demo.txt"; uploadFile(signedUrl, filePath); return 0; }
Android
package com.example.signurlupload; import android.os.AsyncTask; import android.util.Log; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; public class SignUrlUploadActivity { private static final String TAG = "SignUrlUploadActivity"; public void uploadFile(String signedUrl, String filePath) { new UploadTask().execute(signedUrl, filePath); } private class UploadTask extends AsyncTask<String, Void, String> { @Override protected String doInBackground(String... params) { String signedUrl = params[0]; String filePath = params[1]; HttpURLConnection connection = null; DataOutputStream dos = null; FileInputStream fis = null; try { URL url = new URL(signedUrl); connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("PUT"); connection.setDoOutput(true); connection.setRequestProperty("Content-Type", "application/octet-stream"); fis = new FileInputStream(filePath); dos = new DataOutputStream(connection.getOutputStream()); byte[] buffer = new byte[1024]; int length; while ((length = fis.read(buffer)) != -1) { dos.write(buffer, 0, length); } dos.flush(); dos.close(); fis.close(); int responseCode = connection.getResponseCode(); Log.d(TAG, "Status code: " + responseCode); if (responseCode == 200) { Log.d(TAG, "The object is uploaded by using the library."); } return "Object uploaded. Status code: " + responseCode; } catch (IOException e) { e.printStackTrace(); return "Upload failed: " + e.getMessage(); } finally { if (connection != null) { connection.disconnect(); } } } @Override protected void onPostExecute(String result) { Log.d(TAG, result); } } public static void main(String[] args) { SignUrlUploadActivity activity = new SignUrlUploadActivity(); // Replace <signedUrl> with the presigned URL. String signedUrl = "<signedUrl>"; // Specify the full path of the local file that you want to upload. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. String filePath = "C:\\Users\\demo.txt"; activity.uploadFile(signedUrl, filePath); } }
Other scenarios
Use a presigned URL that contains specific request headers and user metadata to upload an object
Use presigned URLs to upload an object in parts
Use a presigned URL to upload an object and set the upload callback parameters
FAQ
When I use a presigned URL to upload a local file, will the file upload fail if the presigned URL expires during the upload?
If I do not specify request headers and user metadata when I generate a URL, do I need to specify request headers and user metadata when I use the URL to upload a local file?
References
For the complete sample code for generating a URL presigned by using the signature algorithm V4, visit GitHub.
For information about the API operation that you can call to upload a local file by using a presigned URL, see GeneratePresignedUrlRequest.