Secara default, file dalam bucket Object Storage Service (OSS) bersifat privat dan hanya dapat diakses oleh pemiliknya. Anda dapat menggunakan OSS C# Software Development Kit (SDK) untuk menghasilkan URL yang ditandatangani guna memberikan izin kepada pengguna lain agar dapat mengunggah file. Saat menghasilkan URL tersebut, Anda dapat menetapkan waktu kedaluwarsa tertentu untuk membatasi durasi akses. URL yang ditandatangani dapat digunakan beberapa kali sebelum kedaluwarsa; namun, unggahan berulang dapat menimpa file yang sama. Setelah URL kedaluwarsa, URL tersebut tidak lagi dapat digunakan untuk mengunggah file, sehingga Anda perlu menghasilkan URL yang ditandatangani baru.
Perhatian
Topik ini menggunakan titik akhir publik wilayah China (Hangzhou). Untuk mengakses OSS dari layanan Alibaba Cloud lainnya dalam wilayah yang sama, gunakan titik akhir internal. Untuk informasi selengkapnya mengenai wilayah dan titik akhir yang didukung, lihat Wilayah dan titik akhir.
Topik ini memberikan contoh cara membaca kredensial akses dari variabel lingkungan. Untuk informasi selengkapnya tentang konfigurasi kredensial akses, lihat Konfigurasikan kredensial akses (C# SDK V1).
Untuk menghasilkan URL yang ditandatangani guna unggah, Anda harus memiliki izin
oss:PutObject. Untuk informasi selengkapnya, lihat Berikan kebijakan akses kustom kepada RAM user.CatatanSaat menghasilkan URL yang ditandatangani, SDK menggunakan kunci yang disimpan secara lokal untuk menghitung signature berdasarkan algoritma tertentu, lalu menambahkan signature tersebut ke URL guna memastikan validitas dan keamanannya. Proses perhitungan dan pembuatan URL ini dilakukan di sisi klien tanpa mengirim permintaan jaringan ke server. Oleh karena itu, pihak yang memanggil tidak memerlukan izin khusus untuk menghasilkan URL yang ditandatangani. Namun, agar pengguna pihak ketiga dapat melakukan operasi pada sumber daya yang diizinkan melalui URL tersebut, entitas yang memanggil API untuk menghasilkan URL harus telah diberikan izin yang sesuai.
Topik ini memberikan contoh URL yang ditandatangani versi V4. Periode validitas maksimum untuk URL yang ditandatangani V4 adalah 7 hari. Untuk informasi selengkapnya, lihat Signature Version 4 (direkomendasikan).
Jika URL yang ditandatangani yang dihasilkan dari contoh berikut mengandung tanda plus (
+), URL tersebut mungkin tidak dapat diakses. Untuk mengatasi masalah ini, ganti tanda plus (+) dalam URL dengan%2B.Untuk menghasilkan URL yang ditandatangani yang menggunakan protokol HTTPS, atur protokol komunikasi di Endpoint ke HTTPS.
Prosedur
Prosedur berikut menjelaskan cara menggunakan URL yang ditandatangani dengan metode PUT untuk mengunggah file:
Contoh kode
Hasilkan URL yang ditandatangani untuk unggah
using Aliyun.OSS; using Aliyun.OSS.Common; // Tentukan Endpoint untuk wilayah tempat bucket berada. Misalnya, jika bucket berada di wilayah China (Hangzhou), atur Endpoint ke https://oss-cn-hangzhou.aliyuncs.com. var endpoint = "https://oss-cn-hangzhou.aliyuncs.com"; // Dapatkan kredensial akses dari variabel lingkungan. Sebelum menjalankan kode ini, pastikan variabel lingkungan OSS_ACCESS_KEY_ID dan OSS_ACCESS_KEY_SECRET telah dikonfigurasi. var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID"); var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET"); // Tentukan nama bucket, misalnya examplebucket. var bucketName = "examplebucket"; // Tentukan path lengkap objek. Path lengkap tidak mencakup nama bucket. Misalnya, exampledir/exampleobject.txt. var objectName = "exampledir/exampleobject.txt"; var objectContent = "More than just cloud."; // Tentukan wilayah tempat bucket berada. Misalnya, jika bucket berada di wilayah China (Hangzhou), atur wilayah ke cn-hangzhou. const string region = "cn-hangzhou"; // Buat instance ClientConfiguration dan ubah parameter default sesuai kebutuhan. var conf = new ClientConfiguration(); // Atur versi signature ke V4. conf.SignatureVersion = SignatureVersion.V4; // Buat instance OssClient. var client = new OssClient(endpoint, accessKeyId, accessKeySecret, conf); client.SetRegion(region); try { // Hasilkan URL yang ditandatangani. var generatePresignedUriRequest = new GeneratePresignedUriRequest(bucketName, objectName, SignHttpMethod.Put) { // Tetapkan waktu kedaluwarsa URL yang ditandatangani. Nilai default adalah 3600 detik. Expiration = DateTime.Now.AddHours(1), }; var signedUrl = client.GeneratePresignedUri(generatePresignedUriRequest); } catch (OssException ex) { Console.WriteLine("Gagal dengan kode kesalahan: {0}; Info kesalahan: {1}. \nRequestID:{2}\tHostID:{3}", ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId); } catch (Exception ex) { Console.WriteLine("Gagal dengan info kesalahan: {0}", ex.Message); }Pengguna lain mengunggah file menggunakan URL presigned melalui 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 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 unggah:"+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 { 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("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 unggah: %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 diizinkan. 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 unggah: {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 diizinkan. 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
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 sesuai kebutuhan. } }); console.log(`Kode status yang dikembalikan untuk unggah: ${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 diizinkan. 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 kesalahan signature mismatch 403 saat menggunakan Browser.js untuk mengunggah file, hal ini biasanya terjadi karena browser secara otomatis menambahkan header permintaan Content-Type, sedangkan header tersebut tidak ditentukan saat URL presigned dihasilkan. Akibatnya, verifikasi signature gagal. Untuk mengatasi masalah ini, pastikan Anda menentukan header permintaan Content-Type saat menghasilkan URL presigned.
<!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 presigned 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 presigned. */ 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 diizinkan. 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 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("Isi 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 ke 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 unggah: " << 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 diizinkan. 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 unggah: " + 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 diizinkan. 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); } }