デフォルトでは、OSS バケット内のオブジェクトは非公開です。オブジェクト所有者のみがオブジェクトをアップロードする権限を持っています。OSS C# SDK を使用して、他のユーザーがオブジェクトをアップロードできるようにする署名付き URL を生成できます。署名付き URL を生成するときに、有効期限を指定してアクセス期間を制限できます。署名付き URL は、有効期限が切れるまで複数回使用できます。複数のアップロード操作が実行されると、オブジェクトが上書きされる可能性があります。URL の有効期限が切れると、アップロードに使用できなくなります。この場合、新しい署名付き URL を生成する必要があります。
注意事項
このトピックのサンプルコードでは、リージョン ID が
cn-hangzhouである中国 (杭州) リージョンを例として使用しています。デフォルトではパブリックエンドポイントが使用されます。OSS と同じリージョンにある他の Alibaba Cloud サービスから OSS にアクセスする場合は、内部エンドポイントを使用してください。OSS がサポートするリージョンとエンドポイントの詳細については、「OSS のリージョンとエンドポイント」をご参照ください。署名付き URL を生成するために特定の権限は必要ありません。ただし、他のユーザーが署名付き URL を使用してオブジェクトをアップロードできるようにするには、
oss:PutObject権限が必要です。詳細については、「RAM ユーザーにバケット内の複数のディレクトリへのアクセスを許可する」をご参照ください。
プロセス
次の図は、HTTP PUT リクエストを許可する署名付き URL を使用してオブジェクトを OSS にアップロードする方法を示しています。
サンプルコード
オブジェクト所有者が PUT リクエストの署名付き URL を生成します。
重要PUT リクエストの署名付き URL を生成する際にリクエストヘッダーを指定した場合、その署名付き URL を使用して PUT リクエストを開始する際にも同じリクエストヘッダーを含める必要があります。そうしないと、リクエストは失敗し、署名の不一致エラーが報告されます。
using System.Text; using OSS = AlibabaCloud.OSS.V2; // Alibaba Cloud OSS SDK のエイリアスを作成して、後続の使用を簡素化します。 var region = "cn-hangzhou"; // 必須。バケットが配置されているリージョンを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、リージョンを cn-hangzhou に設定します。 var endpoint = null as string; // オプション。OSS へのアクセスに使用するエンドポイントを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、エンドポイントを https://oss-cn-hangzhou.aliyuncs.com に設定します。 var bucket = "your bucket name"; // 必須。バケット名。 var key = "your object key"; // 必須。OSS にアップロードされた後のオブジェクトの名前。 // OSS SDK のデフォルト設定を読み込みます。この設定は、環境変数から認証情報 (AccessKey など) を自動的に読み取ります。 var cfg = OSS.Configuration.LoadDefault(); // 環境変数を使用して ID 検証用の認証情報を取得するように明示的に設定します。フォーマット: OSS_ACCESS_KEY_ID と OSS_ACCESS_KEY_SECRET。 cfg.CredentialsProvider = new OSS.Credentials.EnvironmentVariableCredentialsProvider(); // 設定でバケットのリージョンを設定します。 cfg.Region = region; // エンドポイントが指定されている場合、デフォルトのエンドポイントを上書きします。 if(endpoint != null) { cfg.Endpoint = endpoint; } // 設定情報を使用して OSS クライアントインスタンスを作成します。 using var client = new OSS.Client(cfg); // Presign メソッドを呼び出して、署名付き URL を生成します。 var result = client.Presign(new OSS.Models.PutObjectRequest() { Bucket = bucket, Key = key, }); // アップロードするコンテンツ。 const string content = "hello oss!"; // HttpClient を使用して、署名付き URL を使用してコンテンツをアップロードします。 using var hc = new HttpClient(); var httpResult = await hc.PutAsync(result.Url, new ByteArrayContent(Encoding.UTF8.GetBytes(content))); Console.WriteLine("PutObject done"); // 操作が完了したことを示すメッセージを出力します。 Console.WriteLine($"StatusCode: {httpResult.StatusCode}"); // 応答の HTTP ステータスコード。他のユーザーは、PUT リクエストの署名付き URL を使用してオブジェクトをアップロードします。
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; // <signedUrl> を署名付き URL に置き換えます。 URL signedUrl = new URL("<signedUrl>"); // アップロードするローカルファイルの完全なパスを指定します。ローカルファイルのパスが指定されていない場合、ローカルファイルはサンプルプログラムが属するプロジェクトのパスからアップロードされます。 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("Status code:"+response.getStatusLine().getStatusCode()); if(response.getStatusLine().getStatusCode() == 200){ System.out.println("The object is uploaded by using the library."); } 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 { // ローカルファイルを開きます。 file, err := os.Open(filePath) if err != nil { return fmt.Errorf("Unable to open the local file: %w", err) } defer file.Close() // HTTP クライアントを作成します。 client := &http.Client{} // PUT リクエストを作成します。 req, err := http.NewRequest("PUT", signedUrl, file) if err != nil { return fmt.Errorf("Failed to create the request: %w", err) } // リクエストを送信します。 resp, err := client.Do(req) if err != nil { return fmt.Errorf("Failed to send the request:: %w", err) } defer resp.Body.Close() // 応答を読み取ります。 body, err := io.ReadAll(resp.Body) if err != nil { return fmt.Errorf("Failed to read the request: %w", err) } fmt.Printf("Status code: %d\n", resp.StatusCode) if resp.StatusCode == 200 { fmt.Println("The object is uploaded by using the library.") } fmt.Println(string(body)) return nil } func main() { // <signedUrl> を署名付き URL に置き換えます。 signedUrl := "<signedUrl>" // アップロードするローカルファイルの完全なパスを指定します。ローカルファイルのパスが指定されていない場合、ローカルファイルはサンプルプログラムが属するプロジェクトのパスからアップロードされます。 filePath := "C:\\Users\\demo.txt" err := uploadFile(signedUrl, filePath) if err != nil { fmt.Println("An error occurred: ", err) } }python
import requests def upload_file(signed_url, file_path): try: # アップロードするローカルファイルを開きます。 with open(file_path, 'rb') as file: # PUT リクエストを送信してローカルファイルをアップロードします。 response = requests.put(signed_url, data=file) print(f"Status code: {response.status_code}") if response.status_code == 200: print("The object is uploaded by using the library.") print(response.text) except Exception as e: print(f"An error occurred: {e}") if __name__ == "__main__": # <signedUrl> を生成された署名付き URL に置き換えます。 signed_url = "<signedUrl>" # ローカルファイルの完全なパスを指定します。ローカルファイルのパスが指定されていない場合、ローカルファイルはサンプルプログラムが属するプロジェクトのパスからアップロードされます。 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 { // 読み取りストリームを作成します。 const fileStream = fs.createReadStream(filePath); // PUT リクエストを送信してローカルファイルをアップロードします。 const response = await axios.put(signedUrl, fileStream, { headers: { 'Content-Type': 'application/octet-stream' // Content-Type パラメーターを指定します。 } }); console.log(`Status code: ${response.status}`); if (response.status === 200) { console.log("The object is uploaded by using the library."); } console.log(response.data); } catch (error) { console.error(`An error occurred: ${error.message}`); } } // main 関数を指定します。 (async () => { // <signedUrl> を署名付き URL に置き換えます。 const signedUrl = '<signedUrl>'; // アップロードするローカルファイルの完全なパスを指定します。ローカルファイルのパスが指定されていない場合、ローカルファイルはサンプルプログラムが属するプロジェクトのパスからアップロードされます。 const filePath = 'C:\\Users\\demo.txt'; await uploadFile(signedUrl, filePath); })();browser.js
重要Browser.js と署名付き URL を使用してオブジェクトをアップロードすると、署名の不一致を示す 403 SignatureNotMatch エラーが発生することがあります。これは通常、署名付き URL の生成時に指定されていなかった Content-Type リクエストヘッダーをブラウザが自動的に含めることが原因です。このエラーを防ぐには、署名付き URL を生成する際に Content-Type ヘッダーが指定されていることを確認してください。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>File Upload Example</title> </head> <body> <h1>File Upload Example</h1> <! -- ファイルを選択 --> <input type="file" id="fileInput" /> <button id="uploadButton">Upload File</button> <script> // <signedUrl> をステップ 1 で生成された署名付き URL に置き換えます。 const signedUrl = "<signedUrl>"; document.getElementById('uploadButton').addEventListener('click', async () => { const fileInput = document.getElementById('fileInput'); const file = fileInput.files[0]; if (!file) { alert('Please select a file to upload.'); return; } try { await upload(file, signedUrl); alert('File uploaded successfully!'); } catch (error) { console.error('Error during upload:', error); alert('Upload failed: ' + error.message); } }); /** * ファイルを OSS にアップロードします。 * @param {File} file - アップロードされるファイル。 * @param {string} presignedUrl - 署名付き URL。 */ const upload = async (file, presignedUrl) => { const response = await fetch(presignedUrl, { method: 'PUT', body: file, // ファイル全体をアップロードします。 }); if (!response.ok) { throw new Error(`Upload failed, status: ${response.status}`); } console.log('File uploaded successfully'); }; </script> </body> </html>C#
using System.Net.Http.Headers; // アップロードするローカルファイルの完全なパスを指定します。ローカルファイルのパスが指定されていない場合、ローカルファイルはサンプルプログラムが属するプロジェクトのパスからアップロードされます。 var filePath = "C:\\Users\\demo.txt"; // <signedUrl> を署名付き URL に置き換えます。 var presignedUrl = "<signedUrl>"; // HTTP クライアントとローカルファイルストリームを作成します。 using var httpClient = new HttpClient(); using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read); using var content = new StreamContent(fileStream); // PUT リクエストを作成します。 var request = new HttpRequestMessage(HttpMethod.Put, presignedUrl); request.Content = content; // リクエストを送信します。 var response = await httpClient.SendAsync(request); // 応答を処理します。 if (response.IsSuccessStatusCode) { Console.WriteLine($"Uploaded! Status Code: {response.StatusCode}"); Console.WriteLine("Response Header:"); foreach (var header in response.Headers) { Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}"); } } else { string responseContent = await response.Content.ReadAsStringAsync(); Console.WriteLine($"Upload Failed! Status Code: {response.StatusCode}"); Console.WriteLine("Response content: " + 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) { // 署名付き URL を指定します。 curl_easy_setopt(curl, CURLOPT_URL, signedUrl.c_str()); // リクエストメソッドを PUT に設定します。 curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); // ローカルファイルを開きます。 FILE *file = fopen(filePath.c_str(), "rb"); if (!file) { std::cerr << "Unable to open the file: " << filePath << std::endl; return; } // ローカルファイルのサイズを照会します。 fseek(file, 0, SEEK_END); long fileSize = ftell(file); fseek(file, 0, SEEK_SET); // ローカルファイルのサイズを指定します。 curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fileSize); // 入力ファイルハンドルを指定します。 curl_easy_setopt(curl, CURLOPT_READDATA, file); // リクエストを実行します。 res = curl_easy_perform(curl); if (res != CURLE_OK) { std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl; } else { long httpCode = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode); std::cout << "Status code: " << httpCode << std::endl; if (httpCode == 200) { std::cout << "The object is uploaded by using the network library." << std::endl; } } // ローカルファイルを閉じます。 fclose(file); // cURL ハンドルをクリアします。 curl_easy_cleanup(curl); } curl_global_cleanup(); } int main() { // <signedUrl> を署名付き URL に置き換えます。 std::string signedUrl = "<signedUrl>"; // アップロードするローカルファイルの完全なパスを指定します。ローカルファイルのパスが指定されていない場合、ローカルファイルはサンプルプログラムが属するプロジェクトのパスからアップロードされます。 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, "Status code: " + responseCode); if (responseCode == 200) { Log.d(TAG, "The object is uploaded by using the library."); } return "Object uploaded. Status code: " + responseCode; } catch (IOException e) { e.printStackTrace(); return "Upload failed: " + 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(); // <signedUrl> を署名付き URL に置き換えます。 String signedUrl = "<signedUrl>"; // アップロードするローカルファイルの完全なパスを指定します。ローカルファイルのパスが指定されていない場合、ローカルファイルはサンプルプログラムが属するプロジェクトのパスからアップロードされます。 String filePath = "C:\\Users\\demo.txt"; activity.uploadFile(signedUrl, filePath); } }
シナリオ
よくある質問
一時的な署名を使用してオブジェクトをアップロードし、アップロード中に署名の有効期限が切れた場合、アップロードは失敗しますか?
URL を生成するときにリクエストヘッダーとカスタムメタデータを設定しない場合、アップロードに URL を使用するときにそれらを設定する必要がありますか?
リファレンス
署名付き URL を使用してオブジェクトをアップロードするために使用される完全なサンプルコードについては、「PresignPutObject.cs」をご参照ください。