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 Node.js to generate a presigned URL and share it with a user to allow the user to upload an object. When you generate a presigned URL, you can specify its validity periodto limit the period of time during which the user can upload an object. During this validity period, the user can use the URL to upload an object to the bucket multiple times. If you upload the object multiple times, the uploaded object may be overwritten. After the validity period ends, the user can no longer use the presigned URL for uploading. In this case, you must generate a new presigned URL.
Notes
In this topic, the public endpoint of the China (Hangzhou) region is used. If you want to access OSS from other Alibaba Cloud services in the same region as OSS, use an internal endpoint. For more information about OSS regions and endpoints, see Regions and endpoints.
In this topic, access credentials are obtained from environment variables. For more information about how to configure the access credentials, see Configure access credentials.
To generate a presigned URL for object upload, you must have the
oss:PutObjectpermission. For more information, see Attach a custom policy to a RAM user.NoteWhen you use OSS SDK for Node.js to generate a presigned URL, the SDK uses a specific algorithm based on the key information stored in the local computer to calculate a signature and adds the signature to a URL to ensure the validity and security of the URL. The operations performed to calculate the signature and construct the URL are completed on the client. You do not need to send requests to the server over the network. This way, the caller does not need to be granted specific permissions to use OSS SDK for Node.js to generate a presigned URL. However, to allow third-party users to perform relevant operations on the resources authorized by the presigned URL, you must make sure that the caller that calls the API operations to generate the presigned URL has the corresponding permissions.
In this topic, V4 presigned URLs whose validity period is up to seven days are used. For more information, see Signature version 4 (recommended).
Process
The following figure shows how to use a presigned URL that allows HTTP PUT requests to upload an object to OSS.
Sample code
The object owner generates a presigned URL that allows HTTP PUT requests.
const OSS = require("ali-oss"); // Specify a function used to generate a presigned URL. async function generateSignatureUrl(fileName) { // Obtain the presigned URL. const client = await new OSS({ accessKeyId: 'yourAccessKeyId', accessKeySecret: 'yourAccessKeySecret', bucket: 'examplebucket', region: 'oss-cn-hangzhou', authorizationV4: true }); return await client.signatureUrlV4('PUT', 3600, { headers: {} // Specify the request headers based on the actual request headers. }, fileName); } // Call the function and pass in the object name. generateSignatureUrl('yourFileName').then(url => { console.log('Generated Signature URL:', url); }).catch(err => { console.error('Error generating signature URL:', err); });Use the presigned URL that allows HTTP PUT requests to upload an object.
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 of the upload: "+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 a 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 you use Browser.js code to upload an object based on a presigned URL, you may encounter a 403 error that indicates a signature inconsistency. This error arises from a signature verification failure, which occurs because the browser automatically adds the Content-Type request header, an element that was not specified when the presigned URL was generated. To resolve the error, you must specify the Content-Type header when you generate a presigned URL that is expected to be used in Browser.js code to upload data to OSS.
<!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++
#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); } }
Common scenarios
Generate a presigned URL that includes IMG parameters
Generate a presigned URL that includes the versionId header
FAQ
When I use a presigned URL to upload a local file, is the file uploaded if the URL expires during the upload?
Can I use the POST method to generate a presigned URL?
Reference
For more information about the API operation that you can call to upload a local file by using a presigned URL, see GeneratePresignedUrlRequest.