日本熟妇hd丰满老熟妇,中文字幕一区二区三区在线不卡 ,亚洲成片在线观看,免费女同在线一区二区

Python使用簽名URL上傳

默認(rèn)情況下,OSS Bucket中的文件是私有的,僅文件擁有者擁有訪問權(quán)限。您可以使用OSS Go SDK生成簽名URL,以允許他人通過該URL上傳文件。在生成簽名URL時,可以自定義其過期時間以限制訪問持續(xù)時長。在簽名URL有效期內(nèi),該URL可被多次訪問。超出有效期后,將無法進(jìn)行上傳,此時需要重新生成簽名URL。

注意事項

  • 本文以華東1(杭州)外網(wǎng)Endpoint為例。如果您希望通過與OSS同地域的其他阿里云產(chǎn)品訪問OSS,請使用內(nèi)網(wǎng)Endpoint。關(guān)于OSS支持的RegionEndpoint的對應(yīng)關(guān)系,請參見OSS地域和訪問域名。

  • 本文以從環(huán)境變量讀取訪問憑證為例。如何配置訪問憑證,請參見配置訪問憑證

  • 本文以OSS域名新建OSSClient為例。如果您希望通過自定義域名、STS等方式新建OSSClient,請參見新建OSSClient。

  • 生成用于上傳或預(yù)覽文件的簽名URL時,您必須具有oss:PutObject權(quán)限。具體操作,請參見RAM用戶授權(quán)自定義的權(quán)限策略。

    說明

    生成簽名URL過程中,SDK利用本地存儲的密鑰信息,根據(jù)特定算法計算出簽名(signature),然后將其附加到URL上,以確保URL的有效性和安全性。這一系列計算和構(gòu)造URL的操作都是在客戶端完成,不涉及網(wǎng)絡(luò)請求到服務(wù)端。因此,生成簽名URL時不需要授予調(diào)用者特定權(quán)限。但是,為避免第三方用戶無法對簽名URL授權(quán)的資源執(zhí)行相關(guān)操作,需要確保調(diào)用生成簽名URL接口的身份主體被授予對應(yīng)的權(quán)限。

  • 本文以V4簽名URL為例,有效期最大為7天。更多信息,請參見簽名版本4(推薦)

使用過程

使用PUT方式的簽名URL上傳文件的過程如下:

image

使用簽名URL簡單上傳文件

  1. 文件擁有者生成PUT方法的簽名URL。

    # -*- coding: utf-8 -*-
    import oss2
    from oss2.credentials import EnvironmentVariableCredentialsProvider
    
    # 從環(huán)境變量中獲取訪問憑證。運行本代碼示例之前,請確保已設(shè)置環(huán)境變量OSS_ACCESS_KEY_IDOSS_ACCESS_KEY_SECRET。
    auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider())
    
    # 填寫Bucket所在地域?qū)?yīng)的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。
    endpoint = "https://oss-cn-hangzhou.aliyuncs.com"
    
    # 填寫Endpoint對應(yīng)的Region信息,例如cn-hangzhou。注意,v4簽名下,必須填寫該參數(shù)
    region = "cn-hangzhou"
    
    # yourBucketName填寫存儲空間名稱。
    bucket = oss2.Bucket(auth, endpoint, "yourBucketName", region=region)
    
    # 填寫Object完整路徑,例如exampledir/exampleobject.txt。Object完整路徑中不能包含Bucket名稱。
    object_name = 'exampledir/exampleobject.txt'
    
    # 生成上傳文件的簽名URL,有效時間為60秒。
    # 生成簽名URL時,OSS默認(rèn)會對Object完整路徑中的正斜線(/)進(jìn)行轉(zhuǎn)義,從而導(dǎo)致生成的簽名URL無法直接使用。
    # 設(shè)置slash_safeTrue,OSS不會對Object完整路徑中的正斜線(/)進(jìn)行轉(zhuǎn)義,此時生成的簽名URL可以直接使用。
    url = bucket.sign_url('PUT', object_name, 60, slash_safe=True)
    print('簽名URL的地址為:', url)     
  2. 使用獲取的URL簡單上傳文件:

    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>替換為授權(quán)URL。
            URL signedUrl = new URL("<signedUrl>");
    
            // 填寫本地文件的完整路徑。如果未指定本地路徑,則默認(rèn)從示例程序所屬項目對應(yīng)本地路徑中上傳文件。
            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("返回上傳狀態(tài)碼:"+response.getStatusLine().getStatusCode());
                if(response.getStatusLine().getStatusCode() == 200){
                    System.out.println("使用網(wǎng)絡(luò)庫上傳成功");
                }
                System.out.println(response.toString());
            } catch (Exception e){
                e.printStackTrace();
            } finally {
                response.close();
                httpClient.close();
            }
        }
    }       
    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=LTAI5************%2F20241112%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-signature=ed5a939feb8d79a389572719f7e2939939936d0**********"
    import requests
    
    def upload_file(signed_url, file_path):
        try:
            # 打開文件
            with open(file_path, 'rb') as file:
                # 發(fā)送PUT請求上傳文件
                response = requests.put(signed_url, data=file)
         
            print(f"返回上傳狀態(tài)碼:{response.status_code}")
            if response.status_code == 200:
                print("使用網(wǎng)絡(luò)庫上傳成功")
            print(response.text)
     
        except Exception as e:
            print(f"發(fā)生錯誤:{e}")
    
    if __name__ == "__main__":
        # 將<signedUrl>替換為授權(quán)URL。
        signed_url = "<signedUrl>"
        
        # 填寫本地文件的完整路徑。如果未指定本地路徑,則默認(rèn)從示例程序所屬項目對應(yīng)本地路徑中上傳文件。
        file_path = "C:\\Users\\demo.txt"
    
        upload_file(signed_url, file_path)
    
    const fs = require('fs');
    const axios = require('axios');
    
    async function uploadFile(signedUrl, filePath) {
        try {
            // 創(chuàng)建讀取流
            const fileStream = fs.createReadStream(filePath);
            
            // 發(fā)送PUT請求上傳文件
            const response = await axios.put(signedUrl, fileStream, {
                headers: {
                    'Content-Type': 'application/octet-stream' // 根據(jù)實際情況調(diào)整Content-Type
                }
            });
    
            console.log(`返回上傳狀態(tài)碼:${response.status}`);
            if (response.status === 200) {
                console.log('使用網(wǎng)絡(luò)庫上傳成功');
            }
            console.log(response.data);
        } catch (error) {
            console.error(`發(fā)生錯誤:${error.message}`);
        }
    }
    
    // 主函數(shù)
    (async () => {
        // 將<signedUrl>替換為授權(quán)URL。
        const signedUrl = '<signedUrl>';
        
        // 填寫本地文件的完整路徑。如果未指定本地路徑,則默認(rèn)從示例程序所屬項目對應(yīng)本地路徑中上傳文件。
        const filePath = 'C:\\Users\\demo.txt';
    
        await uploadFile(signedUrl, filePath);
    })();
    #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) {
            // 設(shè)置URL
            curl_easy_setopt(curl, CURLOPT_URL, signedUrl.c_str());
    
            // 設(shè)置請求方法為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);
    
            // 設(shè)置文件大小
            curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fileSize);
    
            // 設(shè)置輸入文件句柄
            curl_easy_setopt(curl, CURLOPT_READDATA, file);
    
            // 執(zhí)行請求
            res = curl_easy_perform(curl);
    
            if (res != CURLE_OK) {
                std::cerr << "curl_easy_perform() 失敗: " << curl_easy_strerror(res) << std::endl;
            } else {
                long httpCode = 0;
                curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
                std::cout << "返回上傳狀態(tài)碼: " << httpCode << std::endl;
    
                if (httpCode == 200) {
                    std::cout << "使用網(wǎng)絡(luò)庫上傳成功" << std::endl;
                }
            }
    
            // 關(guān)閉文件
            fclose(file);
    
            // 清理
            curl_easy_cleanup(curl);
        }
    
        curl_global_cleanup();
    }
    
    int main() {
        // 將<signedUrl>替換為授權(quán)URL。
        std::string signedUrl = "<signedUrl>";
    
        // 填寫本地文件的完整路徑。如果未指定本地路徑,則默認(rèn)從示例程序所屬項目對應(yīng)本地路徑中上傳文件。
        std::string filePath = "C:\\Users\\demo.txt";
    
        uploadFile(signedUrl, filePath);
    
        return 0;
    }
    
    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()
    
    	// 創(chuàng)建一個新的HTTP客戶端
    	client := &http.Client{}
    
    	// 創(chuàng)建一個PUT請求
    	req, err := http.NewRequest("PUT", signedUrl, file)
    	if err != nil {
    		return fmt.Errorf("創(chuàng)建請求失敗: %w", err)
    	}
    
    	// 發(fā)送請求
    	resp, err := client.Do(req)
    	if err != nil {
    		return fmt.Errorf("發(fā)送請求失敗: %w", err)
    	}
    	defer resp.Body.Close()
    
    	// 讀取響應(yīng)
    	body, err := io.ReadAll(resp.Body)
    	if err != nil {
    		return fmt.Errorf("讀取響應(yīng)失敗: %w", err)
    	}
    
    	fmt.Printf("返回上傳狀態(tài)碼: %d\n", resp.StatusCode)
    	if resp.StatusCode == 200 {
    		fmt.Println("使用網(wǎng)絡(luò)庫上傳成功")
    	}
    	fmt.Println(string(body))
    
    	return nil
    }
    
    func main() {
    	// 將<signedUrl>替換為授權(quán)URL。
    	signedUrl := "<signedUrl>"
    
    	// 填寫本地文件的完整路徑。如果未指定本地路徑,則默認(rèn)從示例程序所屬項目對應(yīng)本地路徑中上傳文件。
    	filePath := "C:\\Users\\demo.txt"
    
    	err := uploadFile(signedUrl, filePath)
    	if err != nil {
    		fmt.Println("發(fā)生錯誤:", err)
    	}
    }
    
    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, "返回上傳狀態(tài)碼: " + responseCode);
    
                    if (responseCode == 200) {
                        Log.d(TAG, "使用網(wǎng)絡(luò)庫上傳成功");
                    }
    
                    return "上傳完成,狀態(tài)碼: " + 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>替換為授權(quán)URL。
            String signedUrl = "<signedUrl>";
            // 填寫本地文件的完整路徑。如果未指定本地路徑,則默認(rèn)從示例程序所屬項目對應(yīng)本地路徑中上傳文件。
            String filePath = "C:\\Users\\demo.txt";
            activity.uploadFile(signedUrl, filePath);
        }
    }
    

常見使用場景

使用簽名URL上傳指定請求頭和自定義元數(shù)據(jù)的文件

  1. 獲取簡單上傳的簽名URL:

    # -*- coding: utf-8 -*-
    import oss2
    from oss2.credentials import EnvironmentVariableCredentialsProvider
    
    # 從環(huán)境變量中獲取訪問憑證。運行本代碼示例之前,請確保已設(shè)置環(huán)境變量OSS_ACCESS_KEY_IDOSS_ACCESS_KEY_SECRET。
    auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider())
    
    # 填寫Bucket所在地域?qū)?yīng)的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。
    endpoint = "https://oss-cn-hangzhou.aliyuncs.com"
    
    # 填寫Endpoint對應(yīng)的Region信息,例如cn-hangzhou。注意,v4簽名下,必須填寫該參數(shù)
    region = "cn-hangzhou"
    
    # yourBucketName填寫存儲空間名稱。
    bucket = oss2.Bucket(auth, endpoint, "yourBucketName", region=region)
    
    # 填寫Object完整路徑,例如exampledir/exampleobject.txt。Object完整路徑中不能包含Bucket名稱。
    object_name = 'exampledir/exampleobject.txt'
    
    # 指定Header。
    headers = dict()
    # 指定Content-Type。
    headers['Content-Type'] = 'text/plain'
    # 指定存儲類型。
    headers["x-oss-storage-class"] = "Standard"
    
    # 指定元數(shù)據(jù)
    metadata = {'key1': 'value1', 'key2': 'value2'}
    # 更新headers,添加元數(shù)據(jù)前綴
    for key, value in metadata.items():
        headers[f'x-oss-meta-{key}'] = value
    
    # 生成上傳文件的簽名URL,有效時間為60秒。
    # 生成簽名URL時,OSS默認(rèn)會對Object完整路徑中的正斜線(/)進(jìn)行轉(zhuǎn)義,從而導(dǎo)致生成的簽名URL無法直接使用。
    # 設(shè)置slash_safeTrue,OSS不會對Object完整路徑中的正斜線(/)進(jìn)行轉(zhuǎn)義,此時生成的簽名URL可以直接使用。
    url = bucket.sign_url('PUT', object_name, 60, slash_safe=True, headers=headers)
    print('簽名URL的地址為:', url)
  2. 使用獲取的URL簡單上傳文件:

    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>替換為授權(quán)URL。
            URL signedUrl = new URL("<signedUrl>");
    
            // 填寫本地文件的完整路徑。如果未指定本地路徑,則默認(rèn)從示例程序所屬項目對應(yīng)本地路徑中上傳文件。
            String pathName = "C:\\Users\\demo.txt";
    
            // 設(shè)置請求頭,這里的請求頭信息需要與生成URL時的信息一致。
            Map<String, String> headers = new HashMap<String, String>();
            /*// 指定Object的存儲類型。
            headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());
            // 指定ContentType。
            headers.put(OSSHeaders.CONTENT_TYPE, "text/txt");*/
    
            // 設(shè)置用戶自定義元數(shù)據(jù),這里的用戶自定義元數(shù)據(jù)需要與生成URL時的信息一致。
            Map<String, String> userMetadata = new HashMap<String, String>();
            /*userMetadata.put("key1","value1");
            userMetadata.put("key2","value2");*/
    
            try {
                HttpPut put = new HttpPut(signedUrl.toString());
                System.out.println(put);
                HttpEntity entity = new FileEntity(new File(pathName));
                put.setEntity(entity);
                // 如果生成簽名URL時設(shè)置了header參數(shù),例如用戶元數(shù)據(jù),存儲類型等,則調(diào)用簽名URL上傳文件時,也需要將這些參數(shù)發(fā)送至服務(wù)端。如果簽名和發(fā)送至服務(wù)端的不一致,會報簽名錯誤。
                for(Map.Entry header: headers.entrySet()){
                    put.addHeader(header.getKey().toString(),header.getValue().toString());
                }
                for(Map.Entry meta: userMetadata.entrySet()){
                    // 如果使用userMeta,sdk內(nèi)部會為userMeta拼接"x-oss-meta-"前綴。當(dāng)您使用其他方式生成簽名URL進(jìn)行上傳時,userMeta也需要拼接"x-oss-meta-"前綴。
                    put.addHeader("x-oss-meta-"+meta.getKey().toString(), meta.getValue().toString());
                }
    
                httpClient = HttpClients.createDefault();
    
                response = httpClient.execute(put);
    
                System.out.println("返回上傳狀態(tài)碼:"+response.getStatusLine().getStatusCode());
                if(response.getStatusLine().getStatusCode() == 200){
                    System.out.println("使用網(wǎng)絡(luò)庫上傳成功");
                }
                System.out.println(response.toString());
            } catch (Exception e){
                e.printStackTrace();
            } finally {
                response.close();
                httpClient.close();
            }
        }
    }       
    import requests
    from requests.auth import HTTPBasicAuth
    import os
    
    def upload_file(signed_url, file_path, headers=None, metadata=None):
        """
        使用預(yù)簽名的URL上傳文件到OSS。
    
        :param signed_url: 預(yù)簽名的URL。
        :param file_path: 要上傳的文件的完整路徑。
        :param headers: 可選,自定義HTTP頭部。
        :param metadata: 可選,自定義元數(shù)據(jù)。
        :return: None
        """
        if not headers:
            headers = {}
        if not metadata:
            metadata = {}
    
        # 更新headers,添加元數(shù)據(jù)前綴
        for key, value in metadata.items():
            headers[f'x-oss-meta-{key}'] = value
    
        try:
            with open(file_path, 'rb') as file:
                response = requests.put(signed_url, data=file, headers=headers)
                print(f"返回上傳狀態(tài)碼:{response.status_code}")
                if response.status_code == 200:
                    print("使用網(wǎng)絡(luò)庫上傳成功")
                else:
                    print("上傳失敗")
                print(response.text)
        except Exception as e:
            print(f"發(fā)生錯誤:{e}")
    
    if __name__ == "__main__":
        # 將<signedUrl>替換為授權(quán)URL。
        signed_url = "<signedUrl>"
       
        # 填寫本地文件的完整路徑。如果未指定本地路徑,則默認(rèn)從腳本所在目錄中上傳文件。
        file_path = "C:\\Users\\demo.txt"
    
        # 設(shè)置請求頭,這里的請求頭信息需要與生成URL時的信息一致。
        headers = {
             "Content-Type": "text/txt",
             "x-oss-storage-class": "Standard"
        }
    
        # 設(shè)置用戶自定義元數(shù)據(jù),這里的用戶自定義元數(shù)據(jù)需要與生成URL時的信息一致。
        metadata = {
             "key1": "value1",
             "key2": "value2"
        }
    
        upload_file(signed_url, file_path, headers, metadata)
    
    import android.os.AsyncTask;
    import android.util.Log;
    
    import java.io.DataOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Map.Entry;
    
    public class SignUrlUploadActivity extends AppCompatActivity {
    
        private static final String TAG = "SignUrlUploadActivity";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            // 將<signedUrl>替換為授權(quán)URL。
            String signedUrl = "<signedUrl>";
    
            // 填寫本地文件的完整路徑。如果未指定本地路徑,則默認(rèn)從示例程序所屬項目對應(yīng)本地路徑中上傳文件。
            String pathName = "/storage/emulated/0/demo.txt";
    
            // 設(shè)置請求頭,這里的請求頭信息需要與生成URL時的信息一致。
            Map<String, String> headers = new HashMap<>();
            // headers.put("Content-Type", "text/txt");
            // headers.put("x-oss-storage-class", "Standard");
    
            // 設(shè)置用戶自定義元數(shù)據(jù),這里的用戶自定義元數(shù)據(jù)需要與生成URL時的信息一致。
            Map<String, String> userMetadata = new HashMap<>();
            // userMetadata.put("key1", "value1");
            // userMetadata.put("key2", "value2");
    
            new UploadTask().execute(signedUrl, pathName, headers, userMetadata);
        }
    
        private class UploadTask extends AsyncTask<Object, Void, Integer> {
            @Override
            protected Integer doInBackground(Object... params) {
                String signedUrl = (String) params[0];
                String pathName = (String) params[1];
                Map<String, String> headers = (Map<String, String>) params[2];
                Map<String, String> userMetadata = (Map<String, String>) params[3];
    
                try {
                    URL url = new URL(signedUrl);
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("PUT");
                    connection.setDoOutput(true);
                    connection.setUseCaches(false);
    
                    // 設(shè)置請求頭
                    for (Entry<String, String> header : headers.entrySet()) {
                        connection.setRequestProperty(header.getKey(), header.getValue());
                    }
    
                    // 設(shè)置用戶自定義元數(shù)據(jù)
                    for (Entry<String, String> meta : userMetadata.entrySet()) {
                        connection.setRequestProperty("x-oss-meta-" + meta.getKey(), meta.getValue());
                    }
    
                    // 讀取文件
                    File file = new File(pathName);
                    FileInputStream fileInputStream = new FileInputStream(file);
                    DataOutputStream dos = new DataOutputStream(connection.getOutputStream());
    
                    byte[] buffer = new byte[1024];
                    int count;
                    while ((count = fileInputStream.read(buffer)) != -1) {
                        dos.write(buffer, 0, count);
                    }
    
                    fileInputStream.close();
                    dos.flush();
                    dos.close();
    
                    // 獲取響應(yīng)
                    int responseCode = connection.getResponseCode();
                    Log.d(TAG, "返回上傳狀態(tài)碼:" + responseCode);
                    if (responseCode == 200) {
                        Log.d(TAG, "使用網(wǎng)絡(luò)庫上傳成功");
                    } else {
                        Log.d(TAG, "上傳失敗");
                    }
    
                    InputStream is = connection.getInputStream();
                    byte[] responseBuffer = new byte[1024];
                    StringBuilder responseStringBuilder = new StringBuilder();
                    while ((count = is.read(responseBuffer)) != -1) {
                        responseStringBuilder.append(new String(responseBuffer, 0, count));
                    }
                    Log.d(TAG, responseStringBuilder.toString());
    
                    return responseCode;
                } catch (IOException e) {
                    e.printStackTrace();
                    return -1;
                }
            }
    
            @Override
            protected void onPostExecute(Integer result) {
                super.onPostExecute(result);
                if (result == 200) {
                    Toast.makeText(SignUrlUploadActivity.this, "上傳成功", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(SignUrlUploadActivity.this, "上傳失敗", Toast.LENGTH_SHORT).show();
                }
            }
        }
    }
    
    package main
    
    import (
    	"bytes"
    	"fmt"
    	"io/ioutil"
    	"net/http"
    	"os"
    )
    
    func uploadFile(signedUrl string, filePath string, headers map[string]string, metadata map[string]string) error {
    	// 打開文件
    	file, err := os.Open(filePath)
    	if err != nil {
    		return err
    	}
    	defer file.Close()
    
    	// 讀取文件內(nèi)容
    	fileBytes, err := ioutil.ReadAll(file)
    	if err != nil {
    		return err
    	}
    
    	// 創(chuàng)建請求
    	req, err := http.NewRequest("PUT", signedUrl, bytes.NewBuffer(fileBytes))
    	if err != nil {
    		return err
    	}
    
    	// 設(shè)置請求頭
    	for key, value := range headers {
    		req.Header.Set(key, value)
    	}
    
    	// 設(shè)置用戶自定義元數(shù)據(jù)
    	for key, value := range metadata {
    		req.Header.Set(fmt.Sprintf("x-oss-meta-%s", key), value)
    	}
    
    	// 發(fā)送請求
    	client := &http.Client{}
    	resp, err := client.Do(req)
    	if err != nil {
    		return err
    	}
    	defer resp.Body.Close()
    
    	// 處理響應(yīng)
    	fmt.Printf("返回上傳狀態(tài)碼:%d\n", resp.StatusCode)
    	if resp.StatusCode == 200 {
    		fmt.Println("使用網(wǎng)絡(luò)庫上傳成功")
    	} else {
    		fmt.Println("上傳失敗")
    	}
    	body, _ := ioutil.ReadAll(resp.Body)
    	fmt.Println(string(body))
    
    	return nil
    }
    
    func main() {
    	// 將<signedUrl>替換為授權(quán)URL。
    	signedUrl := "<signedUrl>"
    
    	// 填寫本地文件的完整路徑。如果未指定本地路徑,則默認(rèn)從示例程序所屬項目對應(yīng)本地路徑中上傳文件。
    	filePath := "C:\\Users\\demo.txt"
    
    	// 設(shè)置請求頭,這里的請求頭信息需要與生成URL時的信息一致。
    	headers := map[string]string{
    		// "Content-Type": "text/txt",
    		// "x-oss-storage-class": "Standard",
    	}
    
    	// 設(shè)置用戶自定義元數(shù)據(jù),這里的用戶自定義元數(shù)據(jù)需要與生成URL時的信息一致。
    	metadata := map[string]string{
    		// "key1": "value1",
    		// "key2": "value2",
    	}
    
    	err := uploadFile(signedUrl, filePath, headers, metadata)
    	if err != nil {
    		fmt.Printf("發(fā)生錯誤:%v\n", err)
    	}
    }
    
    const fs = require('fs');
    const axios = require('axios');
    
    async function uploadFile(signedUrl, filePath, headers = {}, metadata = {}) {
        try {
            // 更新headers,添加元數(shù)據(jù)前綴
            for (const [key, value] of Object.entries(metadata)) {
                headers[`x-oss-meta-${key}`] = value;
            }
    
            // 讀取文件流
            const fileStream = fs.createReadStream(filePath);
    
            // 發(fā)送PUT請求
            const response = await axios.put(signedUrl, fileStream, {
                headers: headers
            });
    
            console.log(`返回上傳狀態(tài)碼:${response.status}`);
            if (response.status === 200) {
                console.log("使用網(wǎng)絡(luò)庫上傳成功");
            } else {
                console.log("上傳失敗");
            }
            console.log(response.data);
        } catch (error) {
            console.error(`發(fā)生錯誤:${error.message}`);
        }
    }
    
    // 主函數(shù)
    (async () => {
        // 將<signedUrl>替換為授權(quán)URL。
        const signedUrl = "<signedUrl>";
    
        // 填寫本地文件的完整路徑。如果未指定本地路徑,則默認(rèn)從腳本所在目錄中上傳文件。
        const filePath = "C:\\Users\\demo.txt";
    
        // 設(shè)置請求頭,這里的請求頭信息需要與生成URL時的信息一致。
        const headers = {
            // "Content-Type": "text/txt",
            // "x-oss-storage-class": "Standard"
        };
    
        // 設(shè)置用戶自定義元數(shù)據(jù),這里的用戶自定義元數(shù)據(jù)需要與生成URL時的信息一致。
        const metadata = {
            // "key1": "value1",
            // "key2": "value2"
        };
    
        await uploadFile(signedUrl, filePath, headers, metadata);
    })();
    
    #include <iostream>
    #include <fstream>
    #include <curl/curl.h>
    #include <map>
    #include <string>
    
    // 回調(diào)函數(shù),用于處理HTTP響應(yīng)
    size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* output) {
        size_t totalSize = size * nmemb;
        output->append((char*)contents, totalSize);
        return totalSize;
    }
    
    void uploadFile(const std::string& signedUrl, const std::string& filePath, const std::map<std::string, std::string>& headers, const std::map<std::string, std::string>& metadata) {
        CURL* curl;
        CURLcode res;
        std::string readBuffer;
    
        curl_global_init(CURL_GLOBAL_DEFAULT);
        curl = curl_easy_init();
    
        if (curl) {
            // 設(shè)置URL
            curl_easy_setopt(curl, CURLOPT_URL, signedUrl.c_str());
    
            // 設(shè)置請求方法為PUT
            curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
    
            // 打開文件
            FILE* file = fopen(filePath.c_str(), "rb");
            if (!file) {
                std::cerr << "無法打開文件: " << filePath << std::endl;
                return;
            }
    
            // 設(shè)置文件大小
            fseek(file, 0, SEEK_END);
            long fileSize = ftell(file);
            rewind(file);
    
            // 設(shè)置文件讀取回調(diào)
            curl_easy_setopt(curl, CURLOPT_READDATA, file);
            curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fileSize);
    
            // 設(shè)置請求頭
            struct curl_slist* chunk = nullptr;
            for (const auto& header : headers) {
                std::string headerStr = header.first + ": " + header.second;
                chunk = curl_slist_append(chunk, headerStr.c_str());
            }
            for (const auto& meta : metadata) {
                std::string metaStr = "x-oss-meta-" + meta.first + ": " + meta.second;
                chunk = curl_slist_append(chunk, metaStr.c_str());
            }
            curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
    
            // 設(shè)置響應(yīng)處理回調(diào)
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
    
            // 執(zhí)行請求
            res = curl_easy_perform(curl);
    
            // 檢查響應(yīng)
            if (res != CURLE_OK) {
                std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
            } else {
                long responseCode;
                curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
                std::cout << "返回上傳狀態(tài)碼: " << responseCode << std::endl;
                if (responseCode == 200) {
                    std::cout << "使用網(wǎng)絡(luò)庫上傳成功" << std::endl;
                } else {
                    std::cout << "上傳失敗" << std::endl;
                }
                std::cout << readBuffer << std::endl;
            }
    
            // 清理
            fclose(file);
            curl_slist_free_all(chunk);
            curl_easy_cleanup(curl);
        }
    
        curl_global_cleanup();
    }
    
    int main() {
        // 將<signedUrl>替換為授權(quán)URL。
        std::string signedUrl = "<signedUrl>";
    
        // 填寫本地文件的完整路徑。如果未指定本地路徑,則默認(rèn)從示例程序所屬項目對應(yīng)本地路徑中上傳文件。
        std::string filePath = "C:\\Users\\demo.txt";
    
        // 設(shè)置請求頭,這里的請求頭信息需要與生成URL時的信息一致。
        std::map<std::string, std::string> headers = {
            // {"Content-Type", "text/txt"},
            // {"x-oss-storage-class", "Standard"}
        };
    
        // 設(shè)置用戶自定義元數(shù)據(jù),這里的用戶自定義元數(shù)據(jù)需要與生成URL時的信息一致。
        std::map<std::string, std::string> metadata = {
            // {"key1", "value1"},
            // {"key2", "value2"}
        };
    
        uploadFile(signedUrl, filePath, headers, metadata);
    
        return 0;
    }
    
    curl -X PUT \
         -H "Content-Type: text/txt" \
         -H "x-oss-meta-key1: value1" \
         -H "x-oss-meta-key2: value2" \
         -T "C:\\Users\\demo.txt" \
         "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=LTAI5************%2F20241112%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-signature=ed5a939feb8d79a389572719f7e2939939936d0**********"
    

常見問題

使用臨時簽名進(jìn)行文件上傳時,在上傳過程中簽名過期了,上傳中的文件會失敗嗎?

上傳時不會失敗。

上傳時使用的是預(yù)簽名地址,該url只要是在有效期里(取token的有效期和預(yù)簽名有效期最小值),都可以使用。

如果我在生成URL時未設(shè)置請求頭和自定義元數(shù)據(jù),在使用URL上傳時還需要配置嗎?

不需要配置。

請求頭和自定義元數(shù)據(jù)為非必要參數(shù),如果不設(shè)置請求頭和自定義元數(shù)據(jù)可以將示例中相關(guān)代碼去掉。