Secara default, daftar kontrol akses (ACL) dari sebuah objek dalam bucket Object Storage Service (OSS) diatur ke privat, yang berarti hanya pemilik objek yang memiliki izin untuk mengaksesnya. Topik ini menjelaskan cara menggunakan OSS SDK for PHP untuk menghasilkan URL bertanda tangan yang memungkinkan pengguna mengunggah objek tertentu dalam periode yang ditentukan menggunakan metode HTTP PUT. Selama periode validitas, pengguna dapat mengakses objek tersebut secara berulang menggunakan URL bertanda tangan. Jika URL bertanda tangan kedaluwarsa, Anda dapat membuat ulang URL bertanda tangan untuk memperpanjang akses bagi pengguna.
Catatan
Kode contoh dalam topik ini menggunakan ID Wilayah
cn-hangzhoudari wilayah Hangzhou, Tiongkok. Secara default, titik akhir publik digunakan untuk mengakses sumber daya dalam bucket. Jika Anda ingin mengakses sumber daya di bucket dari layanan Alibaba Cloud lainnya di wilayah yang sama dengan lokasi bucket, gunakan titik akhir internal. Untuk informasi lebih lanjut tentang wilayah dan titik akhir yang didukung, lihat Wilayah dan Titik Akhir.Anda tidak memerlukan izin khusus untuk menghasilkan URL bertanda tangan. Namun, untuk mengizinkan pihak ketiga menggunakan URL bertanda tangan untuk mengunggah objek, Anda harus memiliki izin
oss:PutObject. Untuk informasi lebih lanjut, lihat Memberikan Izin kepada Pengguna RAM Menggunakan Kebijakan Kustom.Dalam topik ini, algoritma tanda tangan V4 digunakan untuk menghasilkan URL bertanda tangan dengan periode validitas hingga 7 hari. Untuk informasi lebih lanjut, lihat (Direkomendasikan) Sertakan Tanda Tangan V4 dalam URL.
Dalam topik ini, kredensial akses diperoleh dari variabel lingkungan. Untuk informasi lebih lanjut, lihat Konfigurasi Kredensial Akses untuk OSS SDK for PHP.
Proses
Gambar berikut menunjukkan cara menggunakan URL bertanda tangan yang mengizinkan permintaan HTTP PUT untuk mengunggah objek ke OSS.
Kode contoh
Pemilik objek menghasilkan URL bertanda tangan yang mengizinkan permintaan HTTP PUT.
PentingJika Anda menentukan header permintaan saat menghasilkan URL bertanda tangan yang mengizinkan permintaan HTTP PUT, pastikan bahwa header permintaan tersebut termasuk dalam permintaan PUT yang dimulai menggunakan URL bertanda tangan. Ini mencegah kegagalan permintaan dan kesalahan tanda tangan.
<?php // Sertakan file autoload untuk memuat dependensi. require_once __DIR__ . '/../vendor/autoload.php'; use AlibabaCloud\Oss\V2 as Oss; // Tentukan dan jelaskan opsi baris perintah. $optsdesc = [ "region" => ['help' => 'Wilayah tempat bucket berada.', 'required' => True], // (Diperlukan) Tentukan wilayah tempat bucket berada. "endpoint" => ['help' => 'Nama domain yang dapat digunakan layanan lain untuk mengakses OSS.', 'required' => False], // (Opsional) Tentukan titik akhir untuk mengakses OSS. "bucket" => ['help' => 'Nama bucket', 'required' => True], // (Diperlukan) Tentukan nama bucket. "key" => ['help' => 'Nama objek', 'required' => True], // (Diperlukan) Tentukan nama objek. ]; // Ubah deskripsi menjadi daftar opsi panjang yang diperlukan oleh getopt. // Tambahkan titik dua (:) di akhir setiap opsi untuk menunjukkan bahwa nilai diperlukan. $longopts = \array_map(function ($key) { return "$key:"; }, array_keys($optsdesc)); // Analisis opsi baris perintah. $options = getopt("", $longopts); // Periksa apakah opsi yang diperlukan hilang. foreach ($optsdesc as $key => $value) { if ($value['required'] === True && empty($options[$key])) { $help = $value['help']; // Dapatkan informasi bantuan. echo "Error: argumen berikut diperlukan: --$key, $help" . PHP_EOL; exit(1); // Keluar dari program jika opsi yang diperlukan hilang. } } // Tetapkan nilai yang diurai dari opsi baris perintah ke variabel yang sesuai. $region = $options["region"]; // Wilayah tempat bucket berada. $bucket = $options["bucket"]; // Nama bucket. $key = $options["key"]; // Nama objek // Muat kredensial akses dari variabel lingkungan. // Gunakan EnvironmentVariableCredentialsProvider untuk mengambil ID AccessKey dan Rahasia AccessKey dari variabel lingkungan. $credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider(); // Gunakan konfigurasi default dari SDK. $cfg = Oss\Config::loadDefault(); $cfg->setCredentialsProvider($credentialsProvider); // Tentukan penyedia kredensial. $cfg->setRegion($region); // Tentukan wilayah tempat bucket berada. if (isset($options["endpoint"])) { $cfg->setEndpoint($options["endpoint"]); // Tentukan titik akhir jika ada yang diberikan. } // Buat instance klien OSS. $client = new Oss\Client($cfg); // Buat objek PutObjectRequest untuk mengunggah data. $request = new Oss\Models\PutObjectRequest(bucket: $bucket, key: $key); // Panggil metode presign untuk menghasilkan permintaan bertanda tangan. $result = $client->presign($request); // Tampilkan hasil operasi presign. // Tampilkan URL bertanda tangan, yang dapat digunakan untuk mengunggah objek yang ditentukan. print( 'put object presign result:' . var_export($result, true) . PHP_EOL . // Detail hasil presign. 'put object url:' . $result->url . PHP_EOL // URL bertanda tangan. );Pengguna menggunakan URL bertanda tangan untuk mengunggah objek.
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("Berhasil diunggah 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 tanggapan. body, err := io.ReadAll(resp.Body) if err != nil { return fmt.Errorf("Gagal membaca tanggapan: %w", err) } fmt.Printf("Kode status yang dikembalikan: %d\n", resp.StatusCode) if resp.StatusCode == 200 { fmt.Println("Berhasil diunggah 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("Berhasil diunggah 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('Berhasil diunggah 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 bertanda tangan dihasilkan, verifikasi tanda tangan gagal. Untuk menyelesaikan masalah ini, Anda harus menentukan header permintaan Content-Type saat menghasilkan URL bertanda tangan.
<!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 bertanda tangan 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 bertanda tangan. */ 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 tanggapan. if (response.IsSuccessStatusCode) { Console.WriteLine($"Berhasil diunggah! 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) { // Setel URL. curl_easy_setopt(curl, CURLOPT_URL, signedUrl.c_str()); // Setel 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); // Setel ukuran file. curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fileSize); // Setel pegangan 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 << "Berhasil diunggah 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, "Berhasil diunggah 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); } }