All Products
Search
Document Center

Object Storage Service:Unggah objek menggunakan URL yang ditandatangani sebelumnya (Java SDK V1)

Last Updated:Sep 24, 2026

Secara default, objek dalam bucket Object Storage Service (OSS) bersifat privat. Hanya pemilik objek yang memiliki izin untuk mengunggah objek. Anda dapat menggunakan OSS SDK for Java untuk menghasilkan URL yang ditandatangani sebelumnya guna memungkinkan pengguna lain mengunggah objek. Saat menghasilkan URL tersebut, Anda dapat menentukan waktu kedaluwarsa untuk membatasi periode validitasnya. URL ini dapat digunakan beberapa kali sebelum kedaluwarsa; jika dilakukan beberapa operasi unggah, objek mungkin akan ditimpa. Setelah URL kedaluwarsa, URL tersebut tidak dapat lagi digunakan untuk unggah, dan Anda harus menghasilkan URL yang ditandatangani sebelumnya yang baru.

Catatan penggunaan

  • Pada topik ini, titik akhir publik wilayah China (Hangzhou) digunakan. Untuk mengakses OSS dari layanan Alibaba Cloud lainnya di wilayah yang sama, gunakan titik akhir internal. Untuk detail tentang wilayah dan titik akhir yang didukung, lihat Wilayah dan titik akhir.

  • Pada topik ini, kredensial akses diperoleh dari variabel lingkungan. Untuk informasi selengkapnya, lihat 配置访问凭证.

  • Topik ini menunjukkan cara membuat instans OSSClient dengan titik akhir OSS. Untuk konfigurasi alternatif, seperti menggunakan domain kustom atau melakukan autentikasi dengan kredensial dari Security Token Service (STS), lihat Konfigurasi klien.

  • Izin tidak diperlukan untuk menghasilkan URL yang ditandatangani sebelumnya. Namun, pihak ketiga hanya dapat berhasil mengunggah file menggunakan URL tersebut jika Anda memiliki izin oss:PutObject. Untuk informasi selengkapnya, lihat Berikan kebijakan akses kustom kepada RAM user.

  • Topik ini menggunakan URL yang ditandatangani sebelumnya versi V4 sebagai contoh. Periode validitas maksimum adalah 7 hari. Untuk informasi selengkapnya, lihat Signature Version 4 (direkomendasikan).

Proses

Untuk mengunggah file menggunakan URL yang ditandatangani dan metode PUT, ikuti prosedur berikut:

Contoh kode

  1. Pemilik objek menghasilkan URL yang ditandatangani sebelumnya untuk permintaan PUT.

    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 {
            // Contoh ini menggunakan titik akhir publik wilayah China (Hangzhou). Tentukan titik akhir yang sebenarnya.
            String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
            // Dapatkan kredensial akses dari variabel lingkungan. Sebelum menjalankan kode contoh, pastikan variabel lingkungan OSS_ACCESS_KEY_ID dan OSS_ACCESS_KEY_SECRET telah dikonfigurasi.
            EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
            // Tentukan nama bucket, misalnya examplebucket.
            String bucketName = "examplebucket";
            // Tentukan path lengkap objek, misalnya exampleobject.txt. Path lengkap objek tidak boleh mengandung nama bucket.
            String objectName = "exampleobject.txt";
            // Tentukan wilayah tempat bucket berada. Misalnya, jika bucket berada di wilayah China (Hangzhou), atur wilayah menjadi cn-hangzhou.
            String region = "cn-hangzhou";
    
            // Buat instans OSSClient.
            // Setelah instans OSSClient tidak digunakan lagi, panggil metode shutdown untuk melepaskan sumber daya.
            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 {
                // Tentukan waktu kedaluwarsa URL yang ditandatangani sebelumnya yang dihasilkan dalam milidetik. Contoh ini mengatur waktu kedaluwarsa menjadi 1 jam.
                Date expiration = new Date(new Date().getTime() + 3600 * 1000L);
    
                // Hasilkan URL yang ditandatangani sebelumnya.
                GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.PUT);
                // Atur waktu kedaluwarsa.
                request.setExpiration(expiration);
                // Hasilkan URL yang ditandatangani sebelumnya untuk permintaan HTTP PUT.
                signedUrl = ossClient.generatePresignedUrl(request);
                // Cetak URL yang ditandatangani sebelumnya.
                System.out.println("signed url for putObject: " + signedUrl);
    
            } catch (OSSException oe) {
                System.out.println("Terjadi OSSException, yang berarti permintaan Anda sampai ke OSS, "
                        + "tetapi ditolak dengan tanggapan error karena suatu alasan.");
                System.out.println("Pesan Error:" + oe.getErrorMessage());
                System.out.println("Kode Error:" + oe.getErrorCode());
                System.out.println("ID Permintaan:" + oe.getRequestId());
                System.out.println("Host ID:" + oe.getHostId());
            } catch (ClientException ce) {
                System.out.println("Terjadi ClientException, yang berarti klien mengalami "
                        + "masalah internal serius saat mencoba berkomunikasi dengan OSS, "
                        + "seperti tidak dapat mengakses jaringan.");
                System.out.println("Pesan Error:" + ce.getMessage());
            }
        }
    }       
  2. Pengguna lain mengunggah file menggunakan URL yang ditandatangani sebelumnya untuk permintaan PUT.

    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;
    
            // Ganti <signedUrl> dengan URL yang diizinkan.
            URL signedUrl = new URL("<signedUrl>");
    
            // Tentukan path lengkap file lokal. Jika Anda tidak menentukan path lokal, file diunggah dari path proyek program contoh secara default.
            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("Kode status yang dikembalikan untuk unggahan:"+response.getStatusLine().getStatusCode());
                if(response.getStatusLine().getStatusCode() == 200){
                    System.out.println("Unggah berhasil menggunakan pustaka jaringan.");
                }
                System.out.println(response.toString());
            } catch (Exception e){
                e.printStackTrace();
            } finally {
                 if (response != null) {
                     response.close();
                 }
                 if (httpClient != null) {
                     httpClient.close();
                 }
             }
        }
    }       

    Go

    package main
    
    import (
    	"fmt"
    	"io"
    	"net/http"
    	"os"
    )
    
    func uploadFile(signedUrl, filePath string) error {
    	// Buka file.
    	file, err := os.Open(filePath)
    	if err != nil {
    		return fmt.Errorf("Tidak dapat membuka file: %w", err)
    	}
    	defer file.Close()
    
    	// Buat klien HTTP baru.
    	client := &http.Client{}
    
    	// Buat permintaan PUT.
    	req, err := http.NewRequest("PUT", signedUrl, file)
    	if err != nil {
    		return fmt.Errorf("Gagal membuat permintaan: %w", err)
    	}
    
    	// Kirim permintaan.
    	resp, err := client.Do(req)
    	if err != nil {
    		return fmt.Errorf("Gagal mengirim permintaan: %w", err)
    	}
    	defer resp.Body.Close()
    
    	// Baca tanggapan.
    	body, err := io.ReadAll(resp.Body)
    	if err != nil {
    		return fmt.Errorf("Gagal membaca tanggapan: %w", err)
    	}
    
    	fmt.Printf("Kode status yang dikembalikan untuk unggahan: %d\n", resp.StatusCode)
    	if resp.StatusCode == 200 {
    		fmt.Println("Unggah berhasil menggunakan pustaka jaringan.")
    	}
    	fmt.Println(string(body))
    
    	return nil
    }
    
    func main() {
    	// Ganti <signedUrl> dengan URL yang diizinkan.
    	signedUrl := "<signedUrl>"
    
    	// Tentukan path lengkap file lokal. Jika Anda tidak menentukan path lokal, file diunggah dari path proyek program contoh secara default.
    	filePath := "C:\\Users\\demo.txt"
    
    	err := uploadFile(signedUrl, filePath)
    	if err != nil {
    		fmt.Println("Terjadi error:", err)
    	}
    }
    

    python

    import requests
    
    def upload_file(signed_url, file_path):
        try:
            # Buka file.
            with open(file_path, 'rb') as file:
                # Kirim permintaan PUT untuk mengunggah file.
                response = requests.put(signed_url, data=file)
         
            print(f"Kode status yang dikembalikan untuk unggahan: {response.status_code}")
            if response.status_code == 200:
                print("Unggahan berhasil menggunakan pustaka jaringan.")
            print(response.text)
     
        except Exception as e:
            print(f"Terjadi kesalahan: {e}")
    
    if __name__ == "__main__":
        # Ganti <signedUrl> dengan URL yang diotorisasi.
        signed_url = "<signedUrl>"
        
        # Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari jalur proyek contoh program secara default.
        file_path = "C:\\Users\\demo.txt"
    
        upload_file(signed_url, file_path)
    

    Node.js

    Penting

    Jika Anda mengalami error ketidakcocokan signature 403 saat menggunakan Node.js untuk mengunggah file, biasanya hal ini disebabkan oleh header permintaan Content-Type yang secara eksplisit diatur dalam permintaan unggah, tetapi header tersebut tidak disertakan saat URL yang ditandatangani sebelumnya dihasilkan. Ketidakcocokan ini menyebabkan kegagalan verifikasi signature. Untuk mengatasi masalah ini, jangan atur header permintaan Content-Type dalam permintaan unggah, atau tentukan header permintaan Content-Type saat menghasilkan URL yang ditandatangani sebelumnya.

    const fs = require('fs');
    const axios = require('axios');
    
    async function uploadFile(signedUrl, filePath) {
        try {
            // Buat stream baca.
            const fileStream = fs.createReadStream(filePath);
    
            // Kirim permintaan PUT untuk mengunggah file.
            const response = await axios.put(signedUrl, fileStream);
    
            console.log(`Kode status yang dikembalikan untuk unggahan: ${response.status}`);
            if (response.status === 200) {
                console.log('Unggah berhasil menggunakan pustaka jaringan.');
            }
            console.log(response.data);
        } catch (error) {
            console.error(`Terjadi error: ${error.message}`);
        }
    }
    
    // Fungsi utama.
    (async () => {
        // Ganti <signedUrl> dengan URL yang diizinkan.
        const signedUrl = '<signedUrl>';
        
        // Tentukan path lengkap file lokal. Jika Anda tidak menentukan path lokal, file diunggah dari path proyek program contoh secara default.
        const filePath = 'C:\\Users\\demo.txt';
    
        await uploadFile(signedUrl, filePath);
    })();

    browser.js

    Penting

    Jika Anda mengalami error signature mismatch 403 saat menggunakan Browser.js untuk mengunggah file, hal ini biasanya disebabkan oleh browser yang secara otomatis menambahkan header permintaan Content-Type, sedangkan header tersebut tidak disertakan saat menghasilkan URL yang ditandatangani sebelumnya. Ketidakcocokan ini menyebabkan kegagalan verifikasi signature. Untuk mengatasi masalah ini, Anda harus menentukan header permintaan Content-Type saat menghasilkan URL yang ditandatangani sebelumnya.

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Contoh Unggah File</title>
    </head>
    <body>
        <h1>Contoh Unggah File</h1>
    
        <!-- Pilih file -->
        <input type="file" id="fileInput" />
        <button id="uploadButton">Unggah File</button>
    
        <script>
            // Ganti ini dengan URL yang ditandatangani sebelumnya yang dihasilkan pada Langkah 1.
            const signedUrl = "<signedUrl>"; 
    
    
            document.getElementById('uploadButton').addEventListener('click', async () => {
                const fileInput = document.getElementById('fileInput');
                const file = fileInput.files[0];
    
                if (!file) {
                    alert('Silakan pilih file untuk diunggah.');
                    return;
                }
    
                try {
                    await upload(file, signedUrl);
                    alert('File berhasil diunggah!');
                } catch (error) {
                    console.error('Error saat unggah:', error);
                    alert('Unggah gagal: ' + error.message);
                }
            });
    
            /**
             * Unggah file ke OSS.
             * @param {File} file - File yang akan diunggah.
             * @param {string} presignedUrl - URL yang ditandatangani sebelumnya.
             */
            const upload = async (file, presignedUrl) => {
                const response = await fetch(presignedUrl, {
                    method: 'PUT',
                    body: file,  // Unggah seluruh file secara langsung.
                });
    
                if (!response.ok) {
                    throw new Error(`Unggah gagal, status: ${response.status}`);
                }
    
                console.log('File berhasil diunggah');
            };
        </script>
    </body>
    </html>

    C#

    using System.Net.Http.Headers;
    
    // Tentukan path lengkap file lokal. Jika Anda tidak menentukan path lokal, file diunggah dari path proyek program contoh secara default.
    var filePath = "C:\\Users\\demo.txt";
    // Ganti <signedUrl> dengan URL yang diizinkan.
    var presignedUrl = "<signedUrl>";
    
    // Buat klien HTTP dan buka stream file lokal.
    using var httpClient = new HttpClient(); 
    using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
    using var content = new StreamContent(fileStream);
                
    // Buat permintaan PUT.
    var request = new HttpRequestMessage(HttpMethod.Put, presignedUrl);
    request.Content = content;
    
    // Kirim permintaan.
    var response = await httpClient.SendAsync(request);
    
    // Proses tanggapan.
    if (response.IsSuccessStatusCode)
    {
        Console.WriteLine($"Unggah berhasil! Kode status: {response.StatusCode}");
        Console.WriteLine("Header tanggapan:");
        foreach (var header in response.Headers)
        {
            Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}");
        }
    }
    else
    {
        string responseContent = await response.Content.ReadAsStringAsync();
        Console.WriteLine($"Unggah gagal! Kode status: {response.StatusCode}");
        Console.WriteLine("Konten tanggapan: " + 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) {
            // Atur URL.
            curl_easy_setopt(curl, CURLOPT_URL, signedUrl.c_str());
    
            // Atur metode permintaan menjadi PUT.
            curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
    
            // Buka file.
            FILE *file = fopen(filePath.c_str(), "rb");
            if (!file) {
                std::cerr << "Tidak dapat membuka file: " << filePath << std::endl;
                return;
            }
    
            // Dapatkan ukuran file.
            fseek(file, 0, SEEK_END);
            long fileSize = ftell(file);
            fseek(file, 0, SEEK_SET);
    
            // Atur ukuran file.
            curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fileSize);
    
            // Atur handle file input.
            curl_easy_setopt(curl, CURLOPT_READDATA, file);
    
            // Jalankan permintaan.
            res = curl_easy_perform(curl);
    
            if (res != CURLE_OK) {
                std::cerr << "curl_easy_perform() gagal: " << curl_easy_strerror(res) << std::endl;
            } else {
                long httpCode = 0;
                curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
                std::cout << "Kode status yang dikembalikan untuk unggahan: " << httpCode << std::endl;
    
                if (httpCode == 200) {
                    std::cout << "Unggah berhasil menggunakan pustaka jaringan." << std::endl;
                }
            }
    
            // Tutup file.
            fclose(file);
    
            // Bersihkan.
            curl_easy_cleanup(curl);
        }
    
        curl_global_cleanup();
    }
    
    int main() {
        // Ganti <signedUrl> dengan URL yang diizinkan.
        std::string signedUrl = "<signedUrl>";
    
        // Tentukan path lengkap file lokal. Jika Anda tidak menentukan path lokal, file diunggah dari path proyek program contoh secara default.
        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, "Kode status yang dikembalikan untuk unggahan: " + responseCode);
    
                    if (responseCode == 200) {
                        Log.d(TAG, "Unggah berhasil menggunakan pustaka jaringan.");
                    }
    
                    return "Unggah selesai. Kode status: " + responseCode;
    
                } catch (IOException e) {
                    e.printStackTrace();
                    return "Unggah gagal: " + 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();
            // Ganti <signedUrl> dengan URL yang diizinkan.
            String signedUrl = "<signedUrl>";
            // Tentukan path lengkap file lokal. Jika Anda tidak menentukan path lokal, file diunggah dari path proyek program contoh secara default.
            String filePath = "C:\\Users\\demo.txt";
            activity.uploadFile(signedUrl, filePath);
        }
    }
    

Skenario lainnya

Gunakan URL yang ditandatangani sebelumnya untuk mengunggah file dengan header permintaan dan metadata kustom tertentu

  1. Pemilik objek menghasilkan URL yang ditandatangani sebelumnya untuk permintaan PUT yang mencakup header permintaan dan metadata kustom tertentu.

    import com.aliyun.oss.*;
    import com.aliyun.oss.common.auth.*;
    import com.aliyun.oss.common.comm.SignVersion;
    import com.aliyun.oss.internal.OSSHeaders;
    import com.aliyun.oss.model.GeneratePresignedUrlRequest;
    import com.aliyun.oss.model.StorageClass;
    
    import java.net.URL;
    import java.util.*;
    import java.util.Date;
    
    public class GetSignUrl {
        public static void main(String[] args) throws Throwable {
            // Contoh ini menggunakan titik akhir publik wilayah China (Hangzhou). Tentukan titik akhir yang sebenarnya.
            String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
            // Dapatkan kredensial akses dari variabel lingkungan. Sebelum menjalankan kode contoh, pastikan variabel lingkungan OSS_ACCESS_KEY_ID dan OSS_ACCESS_KEY_SECRET telah dikonfigurasi.
            EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
            // Tentukan nama bucket, misalnya examplebucket.
            String bucketName = "examplebucket";
            // Tentukan path lengkap objek, misalnya exampleobject.txt. Path lengkap objek tidak boleh mengandung nama bucket.
            String objectName = "exampleobject.txt";
            // Tentukan wilayah tempat bucket berada. Misalnya, jika bucket berada di wilayah China (Hangzhou), atur wilayah menjadi cn-hangzhou.
            String region = "cn-hangzhou";
    
            // Buat instans OSSClient.
            // Setelah instans OSSClient tidak digunakan lagi, panggil metode shutdown untuk melepaskan sumber daya.
            ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
            clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
            OSS ossClient = OSSClientBuilder.create()
                    .endpoint(endpoint)
                    .credentialsProvider(credentialsProvider)
                    .clientConfiguration(clientBuilderConfiguration)
                    .region(region)
                    .build();
    
            // Atur header permintaan.
            Map<String, String> headers = new HashMap<String, String>();
            // Tentukan StorageClass.
            headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());
            // Tentukan ContentType.
            headers.put(OSSHeaders.CONTENT_TYPE, "text/plain; charset=utf8");
    
            // Atur metadata pengguna kustom.
            Map<String, String> userMetadata = new HashMap<String, String>();
            userMetadata.put("key1","value1");
            userMetadata.put("key2","value2");
    
            URL signedUrl = null;
            try {
                // Tentukan waktu kedaluwarsa URL yang ditandatangani sebelumnya yang dihasilkan dalam milidetik. Contoh ini mengatur waktu kedaluwarsa menjadi 1 jam.
                Date expiration = new Date(new Date().getTime() + 3600 * 1000L);
    
                // Hasilkan URL yang ditandatangani sebelumnya.
                GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.PUT);
                // Atur waktu kedaluwarsa.
                request.setExpiration(expiration);
    
                // Tambahkan header permintaan ke permintaan.
                request.setHeaders(headers);
                // Tambahkan metadata pengguna kustom.
                request.setUserMetadata(userMetadata);
    
                // Hasilkan URL yang ditandatangani sebelumnya untuk permintaan HTTP PUT.
                signedUrl = ossClient.generatePresignedUrl(request);
                // Cetak URL yang ditandatangani sebelumnya.
                System.out.println("signed url for putObject: " + signedUrl);
    
            } catch (OSSException oe) {
                System.out.println("Terjadi OSSException, yang berarti permintaan Anda sampai ke OSS, "
                        + "tetapi ditolak dengan tanggapan error karena suatu alasan.");
                System.out.println("Pesan Error:" + oe.getErrorMessage());
                System.out.println("Kode Error:" + oe.getErrorCode());
                System.out.println("ID Permintaan:" + oe.getRequestId());
                System.out.println("Host ID:" + oe.getHostId());
            } catch (ClientException ce) {
                System.out.println("Terjadi ClientException, yang berarti klien mengalami "
                        + "masalah internal serius saat mencoba berkomunikasi dengan OSS, "
                        + "seperti tidak dapat mengakses jaringan.");
                System.out.println("Pesan Error:" + ce.getMessage());
            }
        }
    }       
  2. Pengguna lain mengunggah file menggunakan URL yang ditandatangani sebelumnya untuk permintaan PUT.

    curl

    curl -X PUT \
         -H "Content-Type: text/plain;charset=utf8" \
         -H "x-oss-storage-class: Standard" \
         -H "x-oss-meta-key1: value1" \
         -H "x-oss-meta-key2: value2" \
         -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******************************************************"

    Java

    package com.aliyun.sample;
    
    import com.aliyun.oss.internal.OSSHeaders;
    import com.aliyun.oss.model.StorageClass;
    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;
    
            // Ganti <signedUrl> dengan URL yang diizinkan.
            URL signedUrl = new URL("<signedUrl>");
    
            // Tentukan path lengkap file lokal. Jika Anda tidak menentukan path lokal, file diunggah dari path proyek program contoh secara default.
            String pathName = "C:\\Users\\demo.txt";
    
            // Atur header permintaan. Informasi header permintaan harus sama dengan informasi yang digunakan saat URL dihasilkan.
            Map<String, String> headers = new HashMap<String, String>();
            //Tentukan kelas penyimpanan objek.
            headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());
            //Tentukan ContentType.
            headers.put(OSSHeaders.CONTENT_TYPE, "text/plain;charset=utf8");
    
            // Atur metadata pengguna kustom. Metadata pengguna kustom harus sama dengan informasi yang digunakan saat URL dihasilkan.
            Map<String, String> userMetadata = new HashMap<String, String>();
            userMetadata.put("key1","value1");
            userMetadata.put("key2","value2");
    
            try {
                HttpPut put = new HttpPut(signedUrl.toString());
                System.out.println(put);
                HttpEntity entity = new FileEntity(new File(pathName));
                put.setEntity(entity);
                // Jika Anda mengatur parameter header, seperti metadata pengguna dan kelas penyimpanan, saat menghasilkan URL yang ditandatangani sebelumnya, Anda juga harus mengirim parameter ini ke server saat menggunakan URL yang ditandatangani sebelumnya untuk mengunggah file. Error signature akan dilaporkan jika parameter yang dikirim ke server tidak konsisten dengan parameter yang ditandatangani.
                for(Map.Entry<String, String> header: headers.entrySet()){
                    put.addHeader(header.getKey(), header.getValue());
                }
                for(Map.Entry<String, String> meta: userMetadata.entrySet()){
                    // Jika Anda menggunakan userMeta, SDK secara internal menambahkan awalan 'x-oss-meta-'. Saat Anda menggunakan metode lain untuk menghasilkan URL yang ditandatangani sebelumnya untuk unggahan, Anda juga harus menambahkan awalan 'x-oss-meta-' ke userMeta.
                    put.addHeader("x-oss-meta-"+meta.getKey(), meta.getValue());
                }
    
                httpClient = HttpClients.createDefault();
    
                response = httpClient.execute(put);
    
                System.out.println("Kode status yang dikembalikan untuk unggahan:"+response.getStatusLine().getStatusCode());
                if(response.getStatusLine().getStatusCode() == 200){
                    System.out.println("Unggah berhasil menggunakan pustaka jaringan.");
                }
                System.out.println(response.toString());
            } catch (Exception e){
                e.printStackTrace();
            } finally {
                if (response != null) {
                    response.close();
                }
                if (httpClient != null) {
                    httpClient.close();
                }
            }
        }
    }

    Go

    package main
    
    import (
    	"bytes"
    	"fmt"
    	"io/ioutil"
    	"net/http"
    	"os"
    )
    
    func uploadFile(signedUrl string, filePath string, headers map[string]string, metadata map[string]string) error {
    	// Buka file.
    	file, err := os.Open(filePath)
    	if err != nil {
    		return err
    	}
    	defer file.Close()
    
    	// Baca konten file.
    	fileBytes, err := ioutil.ReadAll(file)
    	if err != nil {
    		return err
    	}
    
    	// Buat permintaan.
    	req, err := http.NewRequest("PUT", signedUrl, bytes.NewBuffer(fileBytes))
    	if err != nil {
    		return err
    	}
    
    	// Atur header permintaan.
    	for key, value := range headers {
    		req.Header.Set(key, value)
    	}
    
    	// Atur metadata pengguna kustom.
    	for key, value := range metadata {
    		req.Header.Set(fmt.Sprintf("x-oss-meta-%s", key), value)
    	}
    
    	// Kirim permintaan.
    	client := &http.Client{}
    	resp, err := client.Do(req)
    	if err != nil {
    		return err
    	}
    	defer resp.Body.Close()
    
    	// Proses tanggapan.
    	fmt.Printf("Kode status yang dikembalikan untuk unggahan: %d\n", resp.StatusCode)
    	if resp.StatusCode == 200 {
    		fmt.Println("Unggah berhasil menggunakan pustaka jaringan.")
    	} else {
    		fmt.Println("Unggah gagal.")
    	}
    	body, _ := ioutil.ReadAll(resp.Body)
    	fmt.Println(string(body))
    
    	return nil
    }
    
    func main() {
    	// Ganti <signedUrl> dengan URL yang diizinkan.
    	signedUrl := "<signedUrl>"
    
    	// Tentukan path lengkap file lokal. Jika Anda tidak menentukan path lokal, file diunggah dari path proyek program contoh secara default.
    	filePath := "C:\\Users\\demo.txt"
    
    	// Atur header permintaan. Informasi header permintaan harus sama dengan informasi yang digunakan saat URL dihasilkan.
    	headers := map[string]string{
    		"Content-Type": "text/plain;charset=utf8",
    		"x-oss-storage-class": "Standard",
    	}
    
    	// Atur metadata pengguna kustom. Metadata pengguna kustom harus sama dengan informasi yang digunakan saat URL dihasilkan.
    	metadata := map[string]string{
    		"key1": "value1",
    		"key2": "value2",
    	}
    
    	err := uploadFile(signedUrl, filePath, headers, metadata)
    	if err != nil {
    		fmt.Printf("Terjadi error: %v\n", err)
    	}
    }
    

    Python

    import requests
    from requests.auth import HTTPBasicAuth
    import os
    
    def upload_file(signed_url, file_path, headers=None, metadata=None):
        """
        Gunakan URL yang ditandatangani sebelumnya untuk mengunggah file ke OSS.
    
        :param signed_url: URL yang ditandatangani sebelumnya.
        :param file_path: Path lengkap file yang akan diunggah.
        :param headers: Opsional. Header HTTP kustom.
        :param metadata: Opsional. Metadata kustom.
        :return: None
        """
        if not headers:
            headers = {}
        if not metadata:
            metadata = {}
    
        # Perbarui header dan tambahkan awalan metadata.
        for key, value in metadata.items():
            headers[f'x-oss-meta-{key}'] = value
    
        try:
            with open(file_path, 'rb') as file:
                response = requests.put(signed_url, data=file, headers=headers)
                print(f"Kode status yang dikembalikan untuk unggahan: {response.status_code}")
                if response.status_code == 200:
                    print("Unggah berhasil menggunakan pustaka jaringan.")
                else:
                    print("Unggah gagal.")
                print(response.text)
        except Exception as e:
            print(f"Terjadi error: {e}")
    
    if __name__ == "__main__":
        // Ganti <signedUrl> dengan URL yang diizinkan.
        signed_url = "<signedUrl>"
       
        // Tentukan path lengkap file lokal. Jika Anda tidak menentukan path lokal, file diunggah dari direktori tempat skrip berada secara default.
        file_path = "C:\\Users\\demo.txt"
    
        // Atur header permintaan. Informasi header permintaan harus sama dengan informasi yang digunakan saat URL dihasilkan.
        headers = {
             "Content-Type": "text/plain;charset=utf8",
             "x-oss-storage-class": "Standard"
        }
    
        // Atur metadata pengguna kustom. Metadata pengguna kustom harus sama dengan informasi yang digunakan saat URL dihasilkan.
        metadata = {
             "key1": "value1",
             "key2": "value2"
        }
    
        upload_file(signed_url, file_path, headers, metadata)
    

    Node.js

    const fs = require('fs');
    const axios = require('axios');
    
    async function uploadFile(signedUrl, filePath, headers = {}, metadata = {}) {
        try {
            // Perbarui header dan tambahkan awalan metadata.
            for (const [key, value] of Object.entries(metadata)) {
                headers[`x-oss-meta-${key}`] = value;
            }
    
            // Baca stream file.
            const fileStream = fs.createReadStream(filePath);
    
            // Kirim permintaan PUT.
            const response = await axios.put(signedUrl, fileStream, {
                headers: headers
            });
    
            console.log(`Kode status yang dikembalikan untuk unggahan: ${response.status}`);
            if (response.status === 200) {
                console.log("Unggah berhasil menggunakan pustaka jaringan.");
            } else {
                console.log("Unggah gagal.");
            }
            console.log(response.data);
        } catch (error) {
            console.error(`Terjadi error: ${error.message}`);
        }
    }
    
    // Fungsi utama.
    (async () => {
        // Ganti <signedUrl> dengan URL yang diizinkan.
        const signedUrl = "<signedUrl>";
    
        // Tentukan path lengkap file lokal. Jika Anda tidak menentukan path lokal, file diunggah dari direktori tempat skrip berada secara default.
        const filePath = "C:\\Users\\demo.txt";
    
        // Atur header permintaan. Informasi header permintaan harus sama dengan informasi yang digunakan saat URL dihasilkan.
        const headers = {
             "Content-Type": "text/plain;charset=utf8",
             "x-oss-storage-class": "Standard"
        };
    
        // Atur metadata pengguna kustom. Metadata pengguna kustom harus sama dengan informasi yang digunakan saat URL dihasilkan.
        const metadata = {
             "key1": "value1",
             "key2": "value2"
        };
    
        await uploadFile(signedUrl, filePath, headers, metadata);
    })();
    

    Browser.js

    Penting

    Jika Anda mengalami error ketidakcocokan signature 403 saat menggunakan Browser.js untuk mengunggah file, biasanya hal ini disebabkan oleh browser yang secara otomatis menambahkan header permintaan Content-Type, dan header tersebut tidak disertakan saat URL yang ditandatangani sebelumnya dihasilkan. Ketidakcocokan ini menyebabkan kegagalan verifikasi signature. Untuk mengatasi masalah ini, Anda harus menentukan header permintaan Content-Type saat menghasilkan URL yang ditandatangani sebelumnya.

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Contoh Unggah File</title>
    </head>
    <body>
        <h1>Contoh Unggah File (Java SDK)</h1>
    
        <input type="file" id="fileInput" />
        <button id="uploadButton">Unggah File</button>
    
        <script>
            // Ganti ini dengan URL yang ditandatangani sebelumnya yang sebenarnya.
            const signedUrl = "<signedUrl>"; 
    
            document.getElementById('uploadButton').addEventListener('click', async () => {
                const fileInput = document.getElementById('fileInput');
                const file = fileInput.files[0];
    
                if (file) {
                    try {
                        await upload(file, signedUrl);
                    } catch (error) {
                        console.error('Error saat unggah:', error);
                        alert('Unggah gagal: ' + error.message);
                    }
                } else {
                    alert('Silakan pilih file untuk diunggah.');
                }
            });
    
            const upload = async (file, presignedUrl) => {
                const headers = {
                    "Content-Type": "text/plain;charset=utf8",
                    'x-oss-storage-class': 'Standard',
                    'x-oss-meta-key1': 'value1',
                    'x-oss-meta-key2': 'value2'
                };
    
                const response = await fetch(presignedUrl, {
                    method: 'PUT',
                    headers: headers,
                    body: file
                });
    
                if (!response.ok) {
                    throw new Error(`Unggah gagal, status: ${response.status}`);
                }
    
                alert('File berhasil diunggah');
                console.log('File berhasil diunggah');
            };
        </script>
    </body>
    </html>

    C#

    using System.Net.Http.Headers;
    
    // Tentukan path lengkap file lokal. Jika Anda tidak menentukan path lokal, file diunggah dari path proyek program contoh secara default.
    var filePath = "C:\\Users\\demo.txt";
    // Ganti <signedUrl> dengan URL yang diizinkan.
    var presignedUrl = "<signedUrl>";
    
    // Buat klien HTTP dan buka stream file lokal.
    using var httpClient = new HttpClient(); 
    using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
    using var content = new StreamContent(fileStream);
                
    // Buat permintaan PUT.
    var request = new HttpRequestMessage(HttpMethod.Put, presignedUrl);
    request.Content = content;
    
    // Jika Anda mengatur parameter header, seperti metadata pengguna dan kelas penyimpanan, saat menghasilkan URL yang ditandatangani sebelumnya, Anda juga harus mengirim parameter ini ke server saat menggunakan URL yang ditandatangani sebelumnya untuk mengunggah file. Error signature akan dilaporkan jika parameter yang dikirim ke server tidak konsisten dengan parameter yang ditandatangani.
    // Atur header permintaan. Informasi header permintaan harus sama dengan informasi yang digunakan saat URL dihasilkan.
    request.Content.Headers.ContentType = new MediaTypeHeaderValue("text/plain") { CharSet = "utf8" };  // Tentukan ContentType.       
    // Atur metadata pengguna kustom. Metadata pengguna kustom harus sama dengan informasi yang digunakan saat URL dihasilkan.
    request.Content.Headers.Add("x-oss-meta-key1", "value1");
    request.Content.Headers.Add("x-oss-meta-key2", "value2");
    // Tentukan kelas penyimpanan objek.
    request.Content.Headers.Add("x-oss-storage-class", "Standard");
    
    // Cetak header permintaan.
    Console.WriteLine("Header permintaan:");
    foreach (var header in request.Content.Headers)
    {
        Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}");
    }
    
    // Kirim permintaan.
    var response = await httpClient.SendAsync(request);
    
    // Proses tanggapan.
    if (response.IsSuccessStatusCode)
    {
        Console.WriteLine($"Unggah berhasil! Kode status: {response.StatusCode}");
        Console.WriteLine("Header tanggapan:");
        foreach (var header in response.Headers)
        {
            Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}");
        }
    }
    else
    {
        string responseContent = await response.Content.ReadAsStringAsync();
        Console.WriteLine($"Unggah gagal! Kode status: {response.StatusCode}");
        Console.WriteLine("Konten tanggapan: " + responseContent);
    }

    C++

    #include <iostream>
    #include <fstream>
    #include <curl/curl.h>
    #include <map>
    #include <string>
    
    // Fungsi callback untuk menangani tanggapan HTTP.
    size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* output) {
        size_t totalSize = size * nmemb;
        output->append((char*)contents, totalSize);
        return totalSize;
    }
    
    void uploadFile(const std::string& signedUrl, const std::string& filePath, const std::map<std::string, std::string>& headers, const std::map<std::string, std::string>& metadata) {
        CURL* curl;
        CURLcode res;
        std::string readBuffer;
    
        curl_global_init(CURL_GLOBAL_DEFAULT);
        curl = curl_easy_init();
    
        if (curl) {
            // Atur URL.
            curl_easy_setopt(curl, CURLOPT_URL, signedUrl.c_str());
    
            // Atur metode permintaan menjadi PUT.
            curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
    
            // Buka file.
            FILE* file = fopen(filePath.c_str(), "rb");
            if (!file) {
                std::cerr << "Tidak dapat membuka file: " << filePath << std::endl;
                return;
            }
    
            // Atur ukuran file.
            fseek(file, 0, SEEK_END);
            long fileSize = ftell(file);
            rewind(file);
    
            // Atur callback pembacaan file.
            curl_easy_setopt(curl, CURLOPT_READDATA, file);
            curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fileSize);
    
            // Atur header permintaan.
            struct curl_slist* chunk = nullptr;
            for (const auto& header : headers) {
                std::string headerStr = header.first + ": " + header.second;
                chunk = curl_slist_append(chunk, headerStr.c_str());
            }
            for (const auto& meta : metadata) {
                std::string metaStr = "x-oss-meta-" + meta.first + ": " + meta.second;
                chunk = curl_slist_append(chunk, metaStr.c_str());
            }
            curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
    
            // Atur callback penanganan tanggapan.
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
    
            // Jalankan permintaan.
            res = curl_easy_perform(curl);
    
            // Periksa tanggapan.
            if (res != CURLE_OK) {
                std::cerr << "curl_easy_perform() gagal: " << curl_easy_strerror(res) << std::endl;
            } else {
                long responseCode;
                curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
                std::cout << "Kode status yang dikembalikan untuk unggahan: " << responseCode << std::endl;
                if (responseCode == 200) {
                    std::cout << "Unggah berhasil menggunakan pustaka jaringan." << std::endl;
                } else {
                    std::cout << "Unggah gagal." << std::endl;
                }
                std::cout << readBuffer << std::endl;
            }
    
            // Bersihkan.
            fclose(file);
            curl_slist_free_all(chunk);
            curl_easy_cleanup(curl);
        }
    
        curl_global_cleanup();
    }
    
    int main() {
        // Ganti <signedUrl> dengan URL yang diizinkan.
        std::string signedUrl = "<signedUrl>";
    
        // Tentukan path lengkap file lokal. Jika Anda tidak menentukan path lokal, file diunggah dari path proyek program contoh secara default.
        std::string filePath = "C:\\Users\\demo.txt";
    
        // Atur header permintaan. Informasi header permintaan harus sama dengan informasi yang digunakan saat URL dihasilkan.
        std::map<std::string, std::string> headers = {
             {"Content-Type", "text/plain;charset=utf8"},
             {"x-oss-storage-class", "Standard"}
        };
    
        // Atur metadata pengguna kustom. Metadata pengguna kustom harus sama dengan informasi yang digunakan saat URL dihasilkan.
        std::map<std::string, std::string> metadata = {
             {"key1", "value1"},
             {"key2", "value2"}
        };
    
        uploadFile(signedUrl, filePath, headers, metadata);
    
        return 0;
    }
    

    Android

    import android.os.AsyncTask;
    import android.util.Log;
    
    import java.io.DataOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Map.Entry;
    
    public class SignUrlUploadActivity extends AppCompatActivity {
    
        private static final String TAG = "SignUrlUploadActivity";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            // Ganti <signedUrl> dengan URL yang diizinkan.
            String signedUrl = "<signedUrl>";
    
            // Tentukan path lengkap file lokal. Jika Anda tidak menentukan path lokal, file diunggah dari path proyek program contoh secara default.
            String pathName = "/storage/emulated/0/demo.txt";
    
            // Atur header permintaan. Informasi header permintaan harus sama dengan informasi yang digunakan saat URL dihasilkan.
            Map<String, String> headers = new HashMap<>();
            headers.put("Content-Type", "text/plain;charset=utf8");
            headers.put("x-oss-storage-class", "Standard");
    
            // Atur metadata pengguna kustom. Metadata pengguna kustom harus sama dengan informasi yang digunakan saat URL dihasilkan.
            Map<String, String> userMetadata = new HashMap<>();
            userMetadata.put("key1", "value1");
            userMetadata.put("key2", "value2");
    
            new UploadTask().execute(signedUrl, pathName, headers, userMetadata);
        }
    
        private class UploadTask extends AsyncTask<Object, Void, Integer> {
            @Override
            protected Integer doInBackground(Object... params) {
                String signedUrl = (String) params[0];
                String pathName = (String) params[1];
                Map<String, String> headers = (Map<String, String>) params[2];
                Map<String, String> userMetadata = (Map<String, String>) params[3];
    
                try {
                    URL url = new URL(signedUrl);
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("PUT");
                    connection.setDoOutput(true);
                    connection.setUseCaches(false);
    
                    // Atur header permintaan.
                    for (Entry<String, String> header : headers.entrySet()) {
                        connection.setRequestProperty(header.getKey(), header.getValue());
                    }
    
                    // Atur metadata pengguna kustom.
                    for (Entry<String, String> meta : userMetadata.entrySet()) {
                        connection.setRequestProperty("x-oss-meta-" + meta.getKey(), meta.getValue());
                    }
    
                    // Baca file.
                    File file = new File(pathName);
                    FileInputStream fileInputStream = new FileInputStream(file);
                    DataOutputStream dos = new DataOutputStream(connection.getOutputStream());
    
                    byte[] buffer = new byte[1024];
                    int count;
                    while ((count = fileInputStream.read(buffer)) != -1) {
                        dos.write(buffer, 0, count);
                    }
    
                    fileInputStream.close();
                    dos.flush();
                    dos.close();
    
                    // Dapatkan tanggapan.
                    int responseCode = connection.getResponseCode();
                    Log.d(TAG, "Kode status yang dikembalikan untuk unggahan: " + responseCode);
                    if (responseCode == 200) {
                        Log.d(TAG, "Unggah berhasil menggunakan pustaka jaringan.");
                    } else {
                        Log.d(TAG, "Unggah gagal.");
                    }
    
                    InputStream is = connection.getInputStream();
                    byte[] responseBuffer = new byte[1024];
                    StringBuilder responseStringBuilder = new StringBuilder();
                    while ((count = is.read(responseBuffer)) != -1) {
                        responseStringBuilder.append(new String(responseBuffer, 0, count));
                    }
                    Log.d(TAG, responseStringBuilder.toString());
    
                    return responseCode;
                } catch (IOException e) {
                    e.printStackTrace();
                    return -1;
                }
            }
    
            @Override
            protected void onPostExecute(Integer result) {
                super.onPostExecute(result);
                if (result == 200) {
                    Toast.makeText(SignUrlUploadActivity.this, "Unggah berhasil.", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(SignUrlUploadActivity.this, "Unggah gagal.", Toast.LENGTH_SHORT).show();
                }
            }
        }
    }
    

Gunakan URL yang ditandatangani sebelumnya untuk melakukan unggah multi-bagian

Untuk melakukan unggah multi-bagian menggunakan URL yang ditandatangani sebelumnya, Anda harus mengonfigurasi ukuran bagian dan menghasilkan URL yang ditandatangani sebelumnya untuk setiap bagian. Kode contoh berikut memberikan ilustrasi:

import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.common.utils.CRC64;
import com.aliyun.oss.internal.Mimetypes;
import com.aliyun.oss.model.*;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.BufferedHttpEntity;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.Date;

public class MultipartUrl {
    public static void main(String[] args) throws Throwable {
        // Contoh ini menggunakan titik akhir publik wilayah China (Hangzhou). Tentukan titik akhir yang sebenarnya.
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // Dapatkan kredensial akses dari variabel lingkungan. Sebelum menjalankan kode contoh, pastikan variabel lingkungan OSS_ACCESS_KEY_ID dan OSS_ACCESS_KEY_SECRET telah dikonfigurasi.
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // Tentukan nama bucket, misalnya examplebucket.
        String bucketName = "examplebucket";
        // Tentukan path lengkap objek, misalnya exampleobject.txt. Path lengkap objek tidak boleh mengandung nama bucket.
        String objectName = "exampleobject.txt";
        // Tentukan path lengkap file lokal. Jika Anda tidak menentukan path lokal, file diunggah dari path proyek program contoh secara default.
        String pathName = "D:\\localpath\\examplefile.txt";
        // Tentukan waktu kedaluwarsa URL yang ditandatangani sebelumnya yang dihasilkan dalam milidetik. Contoh ini mengatur waktu kedaluwarsa menjadi 1 jam.
        long expireTime = 3600*1000L;
        // Tentukan wilayah tempat bucket berada. Misalnya, jika bucket berada di wilayah China (Hangzhou), atur wilayah menjadi cn-hangzhou.
        String region = "cn-hangzhou";

        // Buat instans OSSClient.
        // Setelah instans OSSClient tidak digunakan lagi, panggil metode shutdown untuk melepaskan sumber daya.
        ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
        clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
        OSS ossClient = OSSClientBuilder.create()
                .endpoint(endpoint)
                .credentialsProvider(credentialsProvider)
                .clientConfiguration(clientBuilderConfiguration)
                .region(region)
                .build();

        // Buat objek InitiateMultipartUploadRequest.
        InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(bucketName, objectName);
        ObjectMetadata metadata = new ObjectMetadata();
        // Secara otomatis atur ContentType berdasarkan file. Jika parameter ini tidak diatur, ContentType default menjadi application/octet-stream.
        if (metadata.getContentType() == null) {
            metadata.setContentType(Mimetypes.getInstance().getMimetype(new File(pathName), objectName));
        }

        initRequest.setObjectMetadata(metadata);
        // Inisialisasi unggah multi-bagian.
        InitiateMultipartUploadResult upResult = ossClient.initiateMultipartUpload(initRequest);
        // uploadId dikembalikan. uploadId adalah pengidentifikasi unik untuk event unggah multi-bagian. Anda dapat menggunakan uploadId ini untuk melakukan operasi terkait, seperti membatalkan atau mengkueri unggah multi-bagian.
        String uploadId = upResult.getUploadId();

        // partETags adalah kumpulan PartETags. PartETag terdiri dari ETag dan nomor bagian dari suatu bagian.
        List<PartETag> partETags =  new ArrayList<PartETag>();
        // Ukuran setiap bagian dalam byte, yang digunakan untuk menghitung jumlah bagian untuk file.
        long partSize = 1 * 100 * 1024L;   // 100 KB.

        // Tentukan path lengkap file lokal. Jika Anda tidak menentukan path lokal, file diunggah dari path proyek program contoh secara default.
        File sampleFile = new File(pathName);
        long fileLength = sampleFile.length();
        // Jika Anda ingin hanya memiliki satu bagian, atur ukuran bagian menjadi ukuran file.
        // long fileLength = sampleFile.length();
        int partCount = (int) (fileLength / partSize);
        if (fileLength % partSize != 0) {
            partCount++;
        }

        // Atur header permintaan untuk URL yang ditandatangani sebelumnya.
        Map<String, String> headers = new HashMap<String, String>();
        // Tentukan ContentType.
        // headers.put(OSSHeaders.CONTENT_TYPE, "text/plain");


        // Telusuri bagian-bagian untuk mendapatkan signature untuk setiap bagian dan unggah bagian-bagian tersebut.
        // Anda juga dapat mengembalikan URL yang ditandatangani sebelumnya untuk semua bagian sekaligus lalu mengunggahnya secara berurutan. Contoh ini menunjukkan cara mengembalikan satu URL yang ditandatangani sebelumnya dan mengunggah satu bagian menggunakan URL yang ditandatangani sebelumnya.
        for (int i = 0; i < partCount; i++) {
            long startPos = i * partSize;
            long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize;

            /*// Atur verifikasi MD5. Verifikasi MD5 hanya didukung untuk satu bagian.
            FileInputStream inStream = new FileInputStream(pathName);
            // Lewati bagian yang sudah diunggah.
            inStream.skip(startPos);
            BoundedInputStream entity = new BoundedInputStream(inStream, partSize);
            String md5 = BinaryUtil.toBase64String(DigestUtils.md5(entity));
            headers.put("Content-MD5", md5);*/

            String signUrl = getSignUrl(ossClient, bucketName, objectName, HttpMethod.PUT, expireTime, i + 1, uploadId, headers);

            // Unggah file menggunakan URL yang ditandatangani sebelumnya. Contoh ini menggunakan HttpClients.
            putObjectWithHttp(signUrl, pathName, startPos, curPartSize, headers);
        }

        // Asumsikan bahwa saat Anda menggabungkan bagian-bagian, Anda berada di sistem yang berbeda dari sistem yang digunakan untuk mengunggah bagian-bagian tersebut. Dalam kasus ini, Anda harus terlebih dahulu mendaftar bagian-bagian lalu menggabungkannya.
        // Daftar bagian yang diunggah.
        ListPartsRequest listPartsRequest = new ListPartsRequest(bucketName, objectName, uploadId);
        PartListing partListing = ossClient.listParts(listPartsRequest);

        // Telusuri bagian-bagian dan isi partETags.
        for (PartSummary part : partListing.getParts()) {
            PartETag partETag = new PartETag(part.getPartNumber(), part.getETag());
            partETags.add(partETag);
        }

        // Gabungkan bagian-bagian.
        CompleteMultipartUploadRequest completeMultipartUploadRequest =
                new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags);
        // String md5 = BinaryUtil.toBase64String(BinaryUtil.calculateMd5("aaa".getBytes()));
        // Larang menimpa objek yang memiliki nama yang sama.
        // completeMultipartUploadRequest.addHeader("x-oss-forbid-overwrite", "true");

        // Selesaikan unggah multi-bagian.
        CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest);
        System.out.println("Bagian-bagian telah digabungkan dan unggah multi-bagian selesai.");


        // Verifikasi integritas file yang diunggah.
        CRC64 crc = new CRC64();
        InputStream inStream = new FileInputStream(pathName);
        byte[] bytes = new byte[1024];
        int cnt;
        while ((cnt = inStream.read(bytes)) != -1) {
            crc.update(bytes, 0, cnt);
        }

        if(crc.getValue() == completeMultipartUploadResult.getServerCRC()){
            System.out.println("File yang diunggah lengkap.");
        } else {
            System.out.println("File yang diunggah tidak lengkap. Tangani exception.");
        }
    }

    public static void putObjectWithHttp(String signedUrl, String pathName, long startPos, long partSize, Map<String, String> headers) throws IOException {
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        try {
            HttpPut put = new HttpPut(signedUrl);

            FileInputStream inStream = new FileInputStream(pathName);
            // Lewati bagian yang sudah diunggah.
            inStream.skip(startPos);
            InputStreamEntity entity = new InputStreamEntity(inStream, partSize);
            BufferedHttpEntity byteArrayEntity = new BufferedHttpEntity(entity);
            put.setEntity(byteArrayEntity);

            // Jika Anda mengatur parameter header, seperti metadata pengguna dan kelas penyimpanan, saat menghasilkan URL yang ditandatangani sebelumnya, Anda juga harus mengirim parameter ini ke server saat menggunakan URL yang ditandatangani sebelumnya untuk mengunggah file. Error signature akan dilaporkan jika parameter yang dikirim ke server tidak konsisten dengan parameter yang ditandatangani.
            for(Map.Entry header: headers.entrySet()){
                put.addHeader(header.getKey().toString(),header.getValue().toString());
            }

            // Tambahkan mekanisme retry. Jumlah retry diatur menjadi 3. Ini hanya contoh. Atur jumlah retry sesuai kebutuhan bisnis Anda.
            httpClient = HttpClients.custom().setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)).build();

            response = httpClient.execute(put);

            System.out.println("Kode status yang dikembalikan untuk unggahan:"+response.getStatusLine().getStatusCode());
            if(response.getStatusLine().getStatusCode() == 200){
                System.out.println("Unggah berhasil menggunakan pustaka jaringan.");
            }
            System.out.println(response.toString());
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if(response != null){
                response.close();
            }
            if(httpClient != null){
                httpClient.close();
            }
        }
    }

    public static String getSignUrl(OSS ossClient, String bucketName, String objectName, HttpMethod method, long expireTime, int partNum, String uploadId, Map<String, String> headers){
        // Tentukan waktu kedaluwarsa URL yang ditandatangani sebelumnya yang dihasilkan dalam milidetik.
        Date expiration = new Date(new Date().getTime() + expireTime);

        // Hasilkan URL yang ditandatangani sebelumnya.
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, method);
        // Atur waktu kedaluwarsa.
        request.setExpiration(expiration);

        // Tambahkan header permintaan ke permintaan.
        request.setHeaders(headers);

        request.addQueryParameter("partNumber", String.valueOf(partNum));

        request.addQueryParameter("uploadId", uploadId);


        // Hasilkan URL yang ditandatangani sebelumnya untuk permintaan HTTP.
        URL signedUrl = ossClient.generatePresignedUrl(request);
        // Cetak URL yang ditandatangani sebelumnya.
        System.out.println("signed url: " + signedUrl);
        return signedUrl.toString();
    }
}

Gunakan URL yang ditandatangani sebelumnya untuk mengunggah file dan atur parameter callback unggahan

  1. Pemilik objek menghasilkan URL yang ditandatangani sebelumnya untuk permintaan PUT dengan parameter callback unggahan tertentu.

    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 {
            // Contoh ini menggunakan titik akhir publik wilayah China (Hangzhou). Tentukan titik akhir yang sebenarnya.
            String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
            // Dapatkan kredensial akses dari variabel lingkungan. Sebelum menjalankan kode contoh, pastikan variabel lingkungan OSS_ACCESS_KEY_ID dan OSS_ACCESS_KEY_SECRET telah dikonfigurasi.
            EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
            // Tentukan nama bucket, misalnya examplebucket.
            String bucketName = "examplebucket";
            // Tentukan path lengkap objek, misalnya exampleobject.txt. Path lengkap objek tidak boleh mengandung nama bucket.
            String objectName = "exampleobject.txt";
            // Tentukan wilayah tempat bucket berada. Misalnya, jika bucket berada di wilayah China (Hangzhou), atur wilayah menjadi cn-hangzhou.
            String region = "cn-hangzhou";
    
            // Buat instans OSSClient.
            // Setelah instans OSSClient tidak digunakan lagi, panggil metode shutdown untuk melepaskan sumber daya.
            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 {
                // Bangun parameter callback.
                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());
                // Atur header permintaan.
                Map<String, String> headers = new HashMap<String, String>();
                // Tentukan CALLBACK.
                headers.put(OSSHeaders.OSS_HEADER_CALLBACK, callbackBase64);
                // Tentukan CALLBACK-VAR.
                headers.put(OSSHeaders.OSS_HEADER_CALLBACK_VAR, callbackVarBase64);
    
                // Atur waktu kedaluwarsa (3600 detik kemudian).
                Date expiration = new Date(new Date().getTime() + 3600 * 1000);
    
                // Format waktu kedaluwarsa.
                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
                dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
                String expirationStr = dateFormat.format(expiration);
    
                // Bangun permintaan.
                GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName);
                request.setMethod(HttpMethod.PUT);
                request.setExpiration(expiration);
                // Tambahkan header permintaan ke permintaan.
                request.setHeaders(headers);
    
                // Cetak parameter callback dan callback-var.
                System.out.println("callback:"+callbackBase64);
                System.out.println("callback-var:"+callbackVarBase64);
    
                // Hasilkan URL yang ditandatangani sebelumnya.
                URL url = ossClient.generatePresignedUrl(request);
    
                // Cetak hasil.
                System.out.println("method: PUT,");
                System.out.println(" expiration: " + expirationStr + ",");
                System.out.println(" url: " + url);
    
            } catch (OSSException oe) {
                System.out.println("Terjadi OSSException, yang berarti permintaan Anda sampai ke OSS, "
                        + "tetapi ditolak dengan tanggapan error karena suatu alasan.");
                System.out.println("Pesan Error:" + oe.getErrorMessage());
                System.out.println("Kode Error:" + oe.getErrorCode());
                System.out.println("ID Permintaan:" + oe.getRequestId());
                System.out.println("Host ID:" + oe.getHostId());
            } catch (ClientException ce) {
                System.out.println("Terjadi ClientException, yang berarti klien mengalami "
                        + "masalah internal serius saat mencoba berkomunikasi dengan OSS, "
                        + "seperti tidak dapat mengakses jaringan.");
                System.out.println("Pesan Error:" + ce.getMessage());
            }
        }
    }
  2. Pengguna lain mengunggah file menggunakan URL yang ditandatangani sebelumnya untuk permintaan PUT.

    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):
        """
        Unggah file ke OSS menggunakan URL yang telah ditandatangani.
    
        :param signed_url: URL yang telah ditandatangani.
        :param file_path: Path lengkap dari file yang akan diunggah.
        :param headers: Opsional. Header HTTP kustom.
        :return: Tidak ada
        """
        if not headers:
            headers = {}
    
        try:
            with open(file_path, 'rb') as file:
                response = requests.put(signed_url, data=file, headers=headers)
                print(f"Kode status unggahan yang dikembalikan: {response.status_code}")
                if response.status_code == 200:
                    print("Unggahan berhasil menggunakan pustaka jaringan.")
                else:
                    print("Unggahan gagal.")
                print(response.text)
        except Exception as e:
            print(f"Terjadi kesalahan: {e}")
    
    if __name__ == "__main__":
        # Ganti <signedUrl> dengan URL yang diotorisasi.
        signed_url = "<signedUrl>"
    
        # Masukkan path lengkap file lokal. Jika Anda tidak menentukan path lokal, file akan diunggah dari direktori tempat skrip berada secara 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 {
        // Buka file.
        file, err := os.Open(filePath)
        if err != nil {
            return err
        }
        defer file.Close()
    
        // Baca konten file.
        fileBytes, err := io.ReadAll(file)
        if err != nil {
            return err
        }
    
        // Buat permintaan.
        req, err := http.NewRequest("PUT", signedUrl, bytes.NewBuffer(fileBytes))
        if err != nil {
            return err
        }
    
        // Atur header permintaan.
        for key, value := range headers {
            req.Header.Add(key, value)
        }
    
        // Kirim permintaan.
        client := &http.Client{}
        resp, err := client.Do(req)
        if err != nil {
            return err
        }
        defer resp.Body.Close()
    
        // Proses tanggapan.
        fmt.Printf("Kode status unggahan yang dikembalikan: %d\n", resp.StatusCode)
        if resp.StatusCode == 200 {
            fmt.Println("Unggah berhasil menggunakan pustaka jaringan.")
        } else {
            fmt.Println("Unggah gagal.")
        }
        body, _ := io.ReadAll(resp.Body)
        fmt.Println(string(body))
    
        return nil
    }
    
    func main() {
        // Ganti <signedUrl> dengan URL yang diizinkan.
        signedUrl := "<signedUrl>"
        // Masukkan path lengkap file lokal. Jika Anda tidak menentukan path lokal, file diunggah dari path lokal yang sesuai dengan proyek secara default.
        filePath := "C:\\Users\\demo.txt"
    
        // Atur header permintaan. Informasi header di sini harus konsisten dengan informasi yang digunakan untuk menghasilkan URL.
        headers := map[string]string{
            "x-oss-callback":     "eyJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9XHUwMDI2b2JqZWN0PSR7b2JqZWN0fVx1MDAyNnNpemU9JHtzaXplfVx1MDAyNm15X3Zhcl8xPSR7eDpteV92YXIxfVx1MDAyNm15X3Zhcl8yPSR7eDpteV92YXIyfSIsImNhbGxiYWNrQm9keVR5cGUiOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQiLCJjYWxsYmFja1VybCI6Imh0dHA6Ly9leGFtcGxlLmNvbToyMzQ1MCJ9",
            "x-oss-callback-var": "eyJ4Om15X3ZhcjEiOiJ0aGkgaXMgdmFyIDEiLCJ4Om15X3ZhcjIiOiJ0aGkgaXMgdmFyIDIifQ==",
        }
    
        err := uploadFile(signedUrl, filePath, headers)
        if err != nil {
            fmt.Printf("Terjadi error: %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;
    
        // Ganti <signedUrl> dengan URL yang diizinkan.
        URL signedUrl = new URL("<signedUrl>");
    
        // Masukkan path lengkap file lokal. Jika Anda tidak menentukan path lokal, file diunggah dari path lokal yang sesuai dengan proyek secara default.
        String pathName = "C:\\Users\\demo.txt";
    
        // Atur header permintaan, termasuk x-oss-callback dan 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);
          // Jika parameter header diatur saat menghasilkan URL yang ditandatangani sebelumnya, parameter ini juga harus dikirim ke server saat menggunakan URL yang ditandatangani sebelumnya untuk mengunggah file. Jika signature dan parameter yang dikirim ke server tidak cocok, akan terjadi error signature.
          for(Map.Entry<String, String> header: headers.entrySet()){
            put.addHeader(header.getKey(),header.getValue());
          }
    
          httpClient = HttpClients.createDefault();
    
          response = httpClient.execute(put);
    
          System.out.println("Kode status unggahan yang dikembalikan:"+response.getStatusLine().getStatusCode());
          if(response.getStatusLine().getStatusCode() == 200){
            System.out.println("Unggah berhasil menggunakan pustaka jaringan.");
          }
          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 = []) {
        // Periksa apakah file ada.
        if (!file_exists($filePath)) {
            echo "File tidak ada: $filePath\n";
            return;
        }
    
        // Inisialisasi sesi cURL.
        $ch = curl_init();
    
        // Atur opsi 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));
    
        // Jalankan permintaan cURL.
        $response = curl_exec($ch);
    
        // Dapatkan kode status HTTP.
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    
        // Tutup sesi cURL.
        curl_close($ch);
    
        // Keluarkan hasil.
        echo "Kode status unggahan yang dikembalikan: $httpCode\n";
        if ($httpCode == 200) {
            echo "Unggah berhasil menggunakan pustaka jaringan.\n";
        } else {
            echo "Unggah gagal.\n";
        }
        echo $response . "\n";
    }
    
    // Ganti <signedUrl> dengan URL yang diizinkan.
    $signedUrl = "<signedUrl>";
    
    // Masukkan path lengkap file lokal. Jika Anda tidak menentukan path lokal, file diunggah dari direktori tempat skrip berada secara default.
    $filePath = "C:\\Users\\demo.txt";
    
    $headers = [
        "x-oss-callback" => "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9",
        "x-oss-callback-var" => "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==",
    ];
    
    uploadFile($signedUrl, $filePath, $headers);
    
    ?>

FAQ

Jika signature sementara kedaluwarsa selama unggah file, apakah unggah gagal?

Unggahan akan berhasil.

Permintaan unggah harus dimulai selagi URL yang ditandatangani sebelumnya masih valid. Periode validitas URL adalah yang lebih pendek antara periode validitas token dan periode validitas URL yang ditandatangani sebelumnya.

Jika saya tidak mengatur header permintaan dan metadata kustom saat menghasilkan URL, apakah saya perlu mengonfigurasinya saat menggunakan URL untuk unggah?

Tidak perlu konfigurasi.

Header permintaan dan metadata kustom adalah parameter opsional. Jika Anda tidak mengatur parameter ini, Anda dapat menghapus kode terkait dari contoh.

Referensi

  • Untuk kode contoh lengkap untuk menghasilkan URL yang ditandatangani sebelumnya versi V4, lihat contoh GitHub.

  • Untuk informasi selengkapnya tentang operasi API untuk mengunggah file menggunakan URL yang ditandatangani sebelumnya, lihat GeneratePresignedUrlRequest.