デフォルトでは、Object Storage Service(OSS)バケット内のオブジェクトのアクセス制御リスト(ACL)は非公開です。 オブジェクト所有者のみがオブジェクトにアクセスする権限を持っています。 OSS SDK for Python を使用して署名付き URL を生成し、その署名付き URL をユーザーと共有することで、ユーザーがオブジェクトをアップロードできるようにすることができます。 署名付き URL を生成する際に、署名付き URL の有効期間を指定して、ユーザーがオブジェクトをアップロードできる期間を制限することができます。 署名付き URL の有効期間中は、ユーザーはその URL を使用してバケットにオブジェクトを複数回アップロードできます。 署名付き URL の有効期間が終了すると、ユーザーはその署名付き URL を使用してオブジェクトをアップロードできなくなります。 この場合、新しい署名付き URL を生成する必要があります。
使用上の注意
このトピックでは、中国 (杭州) リージョンのパブリックエンドポイントを使用しています。 同じリージョン内の他の Alibaba Cloud サービスから OSS にアクセスするには、内部エンドポイントを使用します。 サポートされているリージョンとエンドポイントの詳細については、「リージョンとエンドポイント」をご参照ください。
このトピックでは、アクセス認証情報は環境変数から取得されます。 アクセス認証情報を設定する方法の詳細については、「アクセス認証情報を設定する (Python SDK V1)」をご参照ください。
このトピックでは、OSS エンドポイントを使用して OSSClient インスタンスを作成します。 カスタムドメイン名または Security Token Service (STS) を使用して OSSClient インスタンスを作成する場合は、「初期化」をご参照ください。
署名付き URL を生成するために特定の権限は必要ありません。 ただし、サードパーティが署名付き URL を使用してオブジェクトをアップロードできるようにするには、
oss:PutObject権限が必要です。 詳細については、「カスタムポリシーを使用して RAM ユーザーに権限を付与する」をご参照ください。このトピックでは、V4 署名アルゴリズムを使用して、最大 7 日間の有効期間を持つ署名付き URL を生成します。 詳細については、「(推奨) 署名付き URL の V4 署名」をご参照ください。
プロセス
次の図は、HTTP PUT リクエストを許可する署名付き URL を使用して OSS にオブジェクトをアップロードする方法を示しています。
サンプルコード
オブジェクト所有者は、HTTP PUT リクエストを許可する署名付き URL を生成します。
# -*- coding: utf-8 -*- import oss2 from oss2.credentials import EnvironmentVariableCredentialsProvider # 環境変数からアクセス認証情報を取得します。サンプルコードを実行する前に、OSS_ACCESS_KEY_ID と OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。 auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider()) # バケットが配置されているリージョンのエンドポイントを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、エンドポイントを https://oss-cn-hangzhou.aliyuncs.com に設定します。 endpoint = "https://oss-cn-hangzhou.aliyuncs.com" # バケットが配置されているリージョンを指定します。例: cn-hangzhou。V4 署名アルゴリズムを使用する場合は、このパラメータが必要です。 region = "cn-hangzhou" # バケットの名前を指定します。 bucket = oss2.Bucket(auth, endpoint, "yourBucketName", region=region) # オブジェクトの完全なパスを指定します。例: exampledir/exampleobject.txt。完全なパスにバケット名を含めないでください。 object_name = 'exampledir/exampleobject.txt' # ローカルファイルをアップロードするために使用される署名付き URL を生成します。署名付き URL の有効期間を 60 秒に設定します。 # デフォルトでは、OSS は署名付き URL の生成時に、オブジェクトの完全なパスにあるスラッシュ (/) をエスケープ文字として認識します。したがって、署名付き URL を直接使用することはできません。 # slash_safe パラメータを True に設定します。こうすることで、OSS はオブジェクトの完全なパスにあるスラッシュ (/) をエスケープ文字として認識しません。この場合、署名付き URL を直接使用できます。 url = bucket.sign_url('PUT', object_name, 60, slash_safe=True) print('The presigned URL:', url)ユーザーは、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 returned:"+response.getStatusLine().getStatusCode()); if(response.getStatusLine().getStatusCode() == 200){ System.out.println("ネットワークライブラリを使用して正常にアップロードされました。"); } 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("ファイルを開けませんでした: %w", err) } defer file.Close() // 新しい HTTP クライアントを作成します。 client := &http.Client{} // PUT リクエストを作成します。 req, err := http.NewRequest("PUT", signedUrl, file) if err != nil { return fmt.Errorf("リクエストの作成に失敗しました: %w", err) } // リクエストを送信します。 resp, err := client.Do(req) if err != nil { return fmt.Errorf("リクエストの送信に失敗しました: %w", err) } defer resp.Body.Close() // レスポンスを読み取ります。 body, err := io.ReadAll(resp.Body) if err != nil { return fmt.Errorf("レスポンスの読み取りに失敗しました: %w", err) } fmt.Printf("Status code returned: %d\n", resp.StatusCode) if resp.StatusCode == 200 { fmt.Println("ネットワークライブラリを使用して正常にアップロードされました。") } 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("エラーが発生しました:", 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 returned: {response.status_code}") if response.status_code == 200: print("ネットワークライブラリを使用して正常にアップロードされました。") print(response.text) except Exception as e: print(f"エラーが発生しました: {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 returned: ${response.status}`); if (response.status === 200) { console.log('ネットワークライブラリを使用して正常にアップロードされました。'); } console.log(response.data); } catch (error) { console.error(`エラーが発生しました: ${error.message}`); } } // メイン関数。 (async () => { // <signedUrl> を承認 URL に置き換えます。 const signedUrl = '<signedUrl>'; // ローカルファイルの完全なパスを指定します。ローカルパスを指定しない場合、デフォルトではサンプルプログラムのプロジェクトに対応するパスからファイルがアップロードされます。 const filePath = 'C:\\Users\\demo.txt'; await uploadFile(signedUrl, filePath); })();browser.js
重要Browser.js を使用してファイルをアップロードし、403 SignatureDoesNotMatch エラーが発生した場合、通常、ブラウザが自動的に Content-Type リクエストヘッダーを追加するためにエラーが発生します。署名付き URL の生成時にこのヘッダーが指定されていない場合、署名の検証は失敗します。この問題を解決するには、署名付き 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>ファイルアップロードの例</title> </head> <body> <h1>ファイルアップロードの例</h1> <!-- ファイルを選択 --> <input type="file" id="fileInput" /> <button id="uploadButton">ファイルをアップロード</button> <script> // ステップ 1 で生成された署名付き URL に置き換えます。 const signedUrl = "<signedUrl>"; document.getElementById('uploadButton').addEventListener('click', async () => { const fileInput = document.getElementById('fileInput'); const file = fileInput.files[0]; if (!file) { alert('アップロードするファイルを選択してください。'); return; } try { await upload(file, signedUrl); alert('ファイルが正常にアップロードされました!'); } catch (error) { console.error('アップロード中にエラーが発生しました:', error); alert('アップロードに失敗しました: ' + 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(`アップロードに失敗しました。ステータス: ${response.status}`); } console.log('ファイルが正常にアップロードされました'); }; </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($"正常にアップロードされました! ステータスコード: {response.StatusCode}"); Console.WriteLine("レスポンスヘッダー:"); foreach (var header in response.Headers) { Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}"); } } else { string responseContent = await response.Content.ReadAsStringAsync(); Console.WriteLine($"アップロードに失敗しました! ステータスコード: {response.StatusCode}"); Console.WriteLine("レスポンスコンテンツ: " + 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 << "ファイルを開けませんでした: " << 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 returned: " << httpCode << std::endl; if (httpCode == 200) { std::cout << "ネットワークライブラリを使用して正常にアップロードされました。" << std::endl; } } // ファイルを閉じます。 fclose(file); // クリーンアップします。 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 returned: " + responseCode); if (responseCode == 200) { Log.d(TAG, "ネットワークライブラリを使用して正常にアップロードされました。"); } return "アップロード完了。ステータスコード: " + responseCode; } catch (IOException e) { e.printStackTrace(); return "アップロード失敗: " + 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); } }