Secara default, daftar kontrol akses (ACL) objek dalam bucket Object Storage Service (OSS) bersifat pribadi, dan hanya pemilik objek yang memiliki izin untuk mengaksesnya. Anda dapat menggunakan OSS SDK untuk Go untuk menghasilkan URL yang ditandatangani, yang kemudian dapat dibagikan kepada pengguna untuk mengizinkan mereka mengunggah objek. Saat menghasilkan URL yang ditandatangani, Anda dapat menentukan periode validitasnya untuk membatasi waktu pengguna dapat mengunggah objek. Selama periode validitas, pengguna dapat menggunakan URL tersebut untuk mengunggah objek ke bucket berkali-kali. Setelah periode validitas berakhir, pengguna tidak dapat lagi menggunakan URL yang ditandatangani untuk mengunggah objek. Untuk memperpanjang akses, Anda dapat menghasilkan ulang URL yang ditandatangani.
Catatan Penggunaan
Dalam 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.
Dalam topik ini, kredensial akses diperoleh dari variabel lingkungan. Untuk informasi lebih lanjut tentang cara mengonfigurasi kredensial akses, lihat Konfigurasikan Kredensial Akses.
Dalam topik ini, instance OSSClient dibuat menggunakan titik akhir OSS. Jika ingin membuat instance OSSClient menggunakan nama domain kustom atau Layanan Token Keamanan (STS), lihat Contoh Konfigurasi untuk Skenario Umum.
Anda tidak memerlukan izin tertentu untuk menghasilkan URL yang ditandatangani. Namun, untuk mengizinkan pihak ketiga menggunakan URL yang ditandatangani untuk mengunggah objek, Anda harus memiliki izin
oss:PutObject. Untuk informasi lebih lanjut, lihat Berikan Izin kepada Pengguna RAM Menggunakan Kebijakan Kustom.Dalam topik ini, algoritma tanda tangan V4 digunakan untuk menghasilkan URL yang ditandatangani dengan periode validitas hingga 7 hari. Untuk informasi lebih lanjut, lihat (Direkomendasikan) Sertakan Tanda Tangan V4 dalam URL.
Proses
Gambar berikut menunjukkan cara menggunakan URL yang ditandatangani untuk mengizinkan permintaan HTTP PUT mengunggah file ke OSS.
Gunakan URL yang Ditandatangani untuk Unggahan Sederhana
Pemilik objek menghasilkan URL yang ditandatangani untuk mengizinkan permintaan HTTP PUT.
package main import ( "log" "github.com/aliyun/aliyun-oss-go-sdk/oss" ) func main() { // Dapatkan kredensial akses dari variabel lingkungan. Sebelum menjalankan kode contoh, pastikan variabel lingkungan OSS_ACCESS_KEY_ID dan OSS_ACCESS_KEY_SECRET telah dikonfigurasi. provider, err := oss.NewEnvironmentVariableCredentialsProvider() if err != nil { log.Printf("Error: %v", err) } // Buat instance OSSClient. // Tentukan titik akhir wilayah tempat bucket berada. Misalnya, jika bucket berada di wilayah China (Hangzhou), atur titik akhir ke https://oss-cn-hangzhou.aliyuncs.com. // Tentukan wilayah bucket. Misalnya, jika bucket Anda berada di wilayah China (Hangzhou), atur wilayah ke cn-hangzhou. clientOptions := []oss.ClientOption{oss.SetCredentialsProvider(&provider)} clientOptions = append(clientOptions, oss.Region("cn-hangzhou")) // Tentukan versi algoritma tanda tangan. clientOptions = append(clientOptions, oss.AuthVersion(oss.AuthV4)) client, err := oss.New("https://oss-cn-hangzhou.aliyuncs.com", "", "", clientOptions...) if err != nil { log.Printf("Error: %v", err) } // Tentukan nama bucket. Contoh: examplebucket. bucketName := "examplebucket" // Tentukan jalur lengkap objek. Contoh: exampleobject.txt. Jangan sertakan nama bucket dalam jalur lengkap. objectName := "exampleobject.txt" bucket, err := client.Bucket(bucketName) if err != nil { log.Printf("Error: %v", err) } // Hasilkan URL yang ditandatangani dan atur periode validitas URL yang ditandatangani menjadi 600 detik. signedURL, err := bucket.SignURL(objectName, oss.HTTPPut, 600) if err != nil { log.Printf("Error: %v", err) } log.Printf("Sign Url:%s\n", signedURL) }Pengguna menggunakan URL yang ditandatangani untuk mengunggah file lokal.
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 otorisasi. URL signedUrl = new URL("<signedUrl>"); // Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari jalur yang sesuai dengan proyek program sampel 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:" + response.getStatusLine().getStatusCode()); if(response.getStatusLine().getStatusCode() == 200){ System.out.println("Diunggah berhasil menggunakan pustaka jaringan."); } 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 { // Buka file. file, err := os.Open(filePath) if err != nil { return fmt.Errorf("Gagal 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 respons. body, err := io.ReadAll(resp.Body) if err != nil { return fmt.Errorf("Gagal membaca respons: %w", err) } fmt.Printf("Kode status yang dikembalikan: %d\n", resp.StatusCode) if resp.StatusCode == 200 { fmt.Println("Diunggah berhasil menggunakan pustaka jaringan.") } fmt.Println(string(body)) return nil } func main() { // Ganti <signedUrl> dengan URL otorisasi. signedUrl := "<signedUrl>" // Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari jalur yang sesuai dengan proyek program sampel secara default. filePath := "C:\\Users\\demo.txt" err := uploadFile(signedUrl, filePath) if err != nil { fmt.Println("Terjadi kesalahan:", 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: {response.status_code}") if response.status_code == 200: print("Diunggah berhasil menggunakan pustaka jaringan.") print(response.text) except Exception as e: print(f"Terjadi kesalahan: {e}") if __name__ == "__main__": # Ganti <signedUrl> dengan URL otorisasi. signed_url = "<signedUrl>" # Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari jalur yang sesuai dengan proyek program sampel secara default. 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 { // Buat aliran baca. const fileStream = fs.createReadStream(filePath); // Kirim permintaan PUT untuk mengunggah file. const response = await axios.put(signedUrl, fileStream, { headers: { 'Content-Type': 'application/octet-stream' // Sesuaikan Content-Type berdasarkan kebutuhan Anda. } }); console.log(`Kode status yang dikembalikan: ${response.status}`); if (response.status === 200) { console.log('Diunggah berhasil menggunakan pustaka jaringan.'); } console.log(response.data); } catch (error) { console.error(`Terjadi kesalahan: ${error.message}`); } } // Fungsi utama. (async () => { // Ganti <signedUrl> dengan URL otorisasi. const signedUrl = '<signedUrl>'; // Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari jalur yang sesuai dengan proyek program sampel secara default. const filePath = 'C:\\Users\\demo.txt'; await uploadFile(signedUrl, filePath); })();browser.js
PentingJika Anda menggunakan Browser.js untuk mengunggah file dan mengalami kesalahan 403 SignatureDoesNotMatch, kesalahan ini biasanya terjadi karena browser secara otomatis menambahkan header permintaan Content-Type. Jika header ini tidak ditentukan saat URL yang ditandatangani dihasilkan, verifikasi tanda tangan gagal. Untuk menyelesaikan masalah ini, Anda harus menentukan header permintaan Content-Type saat menghasilkan URL yang ditandatangani.
<!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 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('Kesalahan selama unggah:', error); alert('Unggah gagal: ' + error.message); } }); /** * Unggah file ke OSS. * @param {File} file - File yang akan diunggah. * @param {string} presignedUrl - URL yang ditandatangani. */ const upload = async (file, presignedUrl) => { const response = await fetch(presignedUrl, { method: 'PUT', body: file, // Unggah seluruh file. }); 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 jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari jalur yang sesuai dengan proyek program sampel secara default. var filePath = "C:\\Users\\demo.txt"; // Ganti <signedUrl> dengan URL otorisasi. var presignedUrl = "<signedUrl>"; // Buat klien HTTP dan buka aliran 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 respons. if (response.IsSuccessStatusCode) { Console.WriteLine($"Diunggah berhasil! Kode status: {response.StatusCode}"); Console.WriteLine("Header respons:"); 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("Isi respons: " + 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 ke PUT. curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); // Buka file. FILE *file = fopen(filePath.c_str(), "rb"); if (!file) { std::cerr << "Gagal 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); // Eksekusi 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: " << httpCode << std::endl; if (httpCode == 200) { std::cout << "Diunggah berhasil menggunakan pustaka jaringan." << std::endl; } } // Tutup file. fclose(file); // Bersihkan. curl_easy_cleanup(curl); } curl_global_cleanup(); } int main() { // Ganti <signedUrl> dengan URL otorisasi. std::string signedUrl = "<signedUrl>"; // Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari jalur yang sesuai dengan proyek program sampel 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: " + responseCode); if (responseCode == 200) { Log.d(TAG, "Diunggah 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 otorisasi. String signedUrl = "<signedUrl>"; // Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari jalur yang sesuai dengan proyek program sampel secara default. String filePath = "C:\\Users\\demo.txt"; activity.uploadFile(signedUrl, filePath); } }