Secara default, daftar kontrol akses (ACL) objek dalam bucket Object Storage Service (OSS) bersifat privat, dan hanya pemilik objek yang memiliki izin untuk mengakses objek tersebut. Anda dapat menggunakan OSS SDK untuk Go guna menghasilkan URL yang ditandatangani sebelumnya, lalu membagikannya kepada pengguna agar mereka dapat mengunggah objek. Saat menghasilkan URL yang ditandatangani sebelumnya, Anda dapat menentukan periode validitasnya untuk membatasi waktu pengguna dalam mengunggah objek. Selama periode validitas tersebut, pengguna dapat menggunakan URL itu untuk mengunggah objek ke bucket beberapa kali. Setelah periode validitas berakhir, pengguna tidak lagi dapat menggunakan URL tersebut untuk mengunggah objek. Untuk memperpanjang akses bagi pengguna, hasilkan kembali URL yang ditandatangani sebelumnya.
Catatan penggunaan
-
Topik ini menggunakan titik akhir publik wilayah China (Hangzhou). Untuk mengakses OSS dari layanan Alibaba Cloud lainnya di wilayah yang sama, gunakan titik akhir internal. Untuk detail wilayah dan titik akhir yang didukung, lihat Wilayah dan titik akhir.
-
Topik ini memperoleh kredensial akses dari variabel lingkungan. Untuk informasi lebih lanjut tentang cara mengonfigurasi kredensial akses, lihat Konfigurasikan kredensial akses (Go SDK V1).
-
Topik ini menunjukkan pembuatan instans OSSClient dengan titik akhir OSS. Untuk konfigurasi alternatif, seperti menggunakan domain kustom atau autentikasi dengan kredensial dari Security Token Service (STS), lihat Konfigurasi client.
-
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 lebih lanjut, lihat Berikan kebijakan akses kustom kepada RAM user. -
Topik ini menggunakan algoritma tanda tangan V4 untuk menghasilkan URL yang ditandatangani sebelumnya dengan periode validitas hingga 7 hari. Untuk informasi lebih lanjut, lihat (Disarankan) Tanda tangan V4 dalam URL yang ditandatangani sebelumnya.
Proses
Gambar berikut menunjukkan cara menggunakan URL yang ditandatangani sebelumnya yang mengizinkan permintaan HTTP PUT untuk mengunggah file ke OSS.
Gunakan URL yang ditandatangani sebelumnya untuk unggah simple
-
Pemilik objek menghasilkan URL yang ditandatangani sebelumnya yang mengizinkan permintaan HTTP PUT.
package main import ( "log" "github.com/aliyun/aliyun-oss-go-sdk/oss" ) func main() { // Peroleh 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 instans OSSClient. // Tentukan titik akhir wilayah tempat bucket berada. Misalnya, jika bucket berada di wilayah China (Hangzhou), atur titik akhir menjadi https://oss-cn-hangzhou.aliyuncs.com. // Tentukan wilayah bucket. Misalnya, jika bucket Anda berada di wilayah China (Hangzhou), atur wilayah menjadi 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 path lengkap objek. Contoh: exampleobject.txt. Jangan sertakan nama bucket dalam path lengkap. objectName := "exampleobject.txt" bucket, err := client.Bucket(bucketName) if err != nil { log.Printf("Error: %v", err) } // Hasilkan URL yang ditandatangani sebelumnya dan atur periode validitasnya 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 sebelumnya 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 yang diotorisasi. URL signedUrl = new URL("<signedUrl>"); // Tentukan path lengkap file lokal. Jika Anda tidak menentukan path lokal, file akan 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 library 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 client 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 untuk unggahan: %d\n", resp.StatusCode) if resp.StatusCode == 200 { fmt.Println("Unggah berhasil menggunakan library jaringan.") } fmt.Println(string(body)) return nil } func main() { // Ganti <signedUrl> dengan URL yang diotorisasi. signedUrl := "<signedUrl>" // Tentukan path lengkap file lokal. Jika Anda tidak menentukan path lokal, file akan diunggah dari path proyek program contoh 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 untuk unggahan: {response.status_code}") if response.status_code == 200: print("Unggah berhasil menggunakan library 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 path lengkap file lokal. Jika Anda tidak menentukan path lokal, file akan diunggah dari path proyek program contoh secara default. file_path = "C:\\Users\\demo.txt" upload_file(signed_url, file_path)Node.js
PentingJika Anda mengalami error ketidakcocokan signature 403 saat menggunakan Node.js untuk mengunggah file, biasanya karena header permintaan Content-Type secara eksplisit diatur dalam permintaan unggah, tetapi header ini 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 library jaringan.'); } console.log(response.data); } catch (error) { console.error(`Terjadi kesalahan: ${error.message}`); } } // Fungsi utama. (async () => { // Ganti <signedUrl> dengan URL yang diotorisasi. const signedUrl = '<signedUrl>'; // Tentukan path lengkap file lokal. Jika Anda tidak menentukan path lokal, file akan diunggah dari path proyek program contoh secara default. const filePath = 'C:\\Users\\demo.txt'; await uploadFile(signedUrl, filePath); })();browser.js
PentingJika Anda mengalami error ketidakcocokan signature 403 saat menggunakan Browser.js untuk mengunggah file, biasanya karena browser secara otomatis menambahkan header permintaan Content-Type, dan header ini 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</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('Kesalahan 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 akan diunggah dari path proyek program contoh secara default. var filePath = "C:\\Users\\demo.txt"; // Ganti <signedUrl> dengan URL yang diotorisasi. var presignedUrl = "<signedUrl>"; // Buat client 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 respons. if (response.IsSuccessStatusCode) { Console.WriteLine($"Unggah 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 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 library jaringan." << std::endl; } } // Tutup file. fclose(file); // Bersihkan. curl_easy_cleanup(curl); } curl_global_cleanup(); } int main() { // Ganti <signedUrl> dengan URL yang diotorisasi. std::string signedUrl = "<signedUrl>"; // Tentukan path lengkap file lokal. Jika Anda tidak menentukan path lokal, file akan 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 library 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 diotorisasi. String signedUrl = "<signedUrl>"; // Tentukan path lengkap file lokal. Jika Anda tidak menentukan path lokal, file akan diunggah dari path proyek program contoh secara default. String filePath = "C:\\Users\\demo.txt"; activity.uploadFile(signedUrl, filePath); } }