Java——API

java江南 發佈 2022-05-22T22:16:48.895939+00:00

騰訊雲 API 全新升級3.0,該版本進行了性能優化且全地域部署、支持就近和按地域接入、訪問時延下降顯著,接口描述更加詳細、錯誤碼描述更加全面、SDK 增加接口級注釋,讓您更加方便快捷的使用騰訊雲產品。公共參數是用於標識用戶和接口簽名的參數,每次請求均需要攜帶這些參數,才能正常發起請求。

騰訊雲 API 全新升級3.0,該版本進行了性能優化且全地域部署、支持就近和按地域接入、訪問時延下降顯著,接口描述更加詳細、錯誤碼描述更加全面、SDK 增加接口級注釋,讓您更加方便快捷的使用騰訊雲產品。這裡針對 Java API 調用方式進行簡單說明。

了解請求結構

1. 服務地址(endpoint)

API 支持就近地域接入(例如:cvm 產品域名為 cvm.tencentcloudapi.com ),也支持指定地域域名訪問(例如: 廣州地域的域名為 cvm.ap-guangzhou.tencentcloudapi.com),各地域參數見下文公共參數中的地域列表,詳情請參見各產品的「請求結構」文檔說明判斷是否支持該地域。

注意

對時延敏感的業務,建議指定帶地域的域名。

2. 通信協議

騰訊雲 API 的所有接口均通過 HTTPS 進行通信,提供高安全性的通信通道。

3. 請求方法

支持的 HTTP 請求方法:

  • POST(推薦)
  • GET

POST 請求支持的 Content-Type 類型:

  • application/json(推薦),必須使用簽名方法 v3(TC3-HMAC-SHA256)。
  • application/x-www-form-urlencoded,必須使用簽名方法 v1(HmacSHA1 或 HmacSHA256)。
  • multipart/form-data(僅部分接口支持),必須使用簽名方法 v3(TC3-HMAC-SHA256)。

GET 請求的請求包大小不得超過32KB。POST 請求使用簽名方法 v1(HmacSHA1、HmacSHA256)時不得超過1MB。POST 請求使用簽名方法 v3(TC3-HMAC-SHA256)時支持10MB。

4. 字符編碼

均使用 UTF-8 編碼。

公共參數

公共參數是用於標識用戶和接口簽名的參數,每次請求均需要攜帶這些參數,才能正常發起請求。

簽名方法 V3 公共參數

簽名方法 v3(有時也稱作 TC3-HMAC-SHA256)相比簽名方法 v1(有些文檔可能會簡稱「簽名方法」),更安全,支持更大的請求包,支持 POST JSON 格式,性能有一定提升,推薦使用該簽名方法計算簽名。使用方法見下文 「簽名方法介紹」 。

參數名稱

類型

必選

描述

X-TC-Action

String

操作的接口名稱。取值參考接口文檔中輸入參數公共參數 Action 的說明。例如雲伺服器的查詢實例列表接口,取值為 DescribeInstances。

X-TC-Region

String

-

地域參數,用來標識希望操作哪個地域的數據。接口接受的地域取值參考接口文檔中輸入參數公共參數 Region 的說明。注意:某些接口不需要傳遞該參數,接口文檔中會對此特別說明,此時即使傳遞該參數也不會生效。

X-TC-Timestamp

Integer

當前 UNIX 時間戳,可記錄發起 API 請求的時間。例如1529223702。注意:如果與伺服器時間相差超過5分鐘,會引起簽名過期錯誤。

X-TC-Version

String

操作的 API 的版本。取值參考接口文檔中入參公共參數 Version 的說明。例如雲伺服器的版本2017-03-12。

Authorization

String

HTTP 標準身份認證頭部欄位,例如:TC3-HMAC-SHA256 Credential=AKIDEXAMPLE/Date/service/tc3_request, SignedHeaders=content-type;host, Signature=72e494ea8**a96525168
其中:

  • TC3-HMAC-SHA256:簽名方法,目前固定取該值。
  • Credential:簽名憑證,AKIDEXAMPLE 是 SecretId。
  • Date 是 UTC 標準時間的日期,取值需要和公共參數 X-TC-Timestamp 換算的 UTC 標準時間日期一致。
  • service 為產品名,通常為域名前綴,例如域名 cvm.tencentcloudapi.com 意味著產品名是 cvm 。本產品取值為 cvm。
  • SignedHeaders:參與簽名計算的頭部信息,content-type 和 host 為必選頭部。
  • Signature:簽名摘要,計算過程詳見下文。

X-TC-Token

String

臨時證書所用的 Token ,需要結合臨時密鑰一起使用。臨時密鑰和 Token 需要到訪問管理服務調用接口獲取。長期密鑰不需要 Token。

簽名方法 V1 公共參數

使用簽名方法 v1(有時會稱作 HmacSHA256 和 HmacSHA1),公共參數需要統一放到請求串中。

參數名稱

類型

必選

描述

Action

String

操作的接口名稱。取值參考接口文檔中輸入參數公共參數 Action 的說明。例如雲伺服器的查詢實例列表接口,取值為 DescribeInstances。

Region

String

-

地域參數,用來標識希望操作哪個地域的數據。接口接受的地域取值參考接口文檔中輸入參數公共參數 Region 的說明。注意:某些接口不需要傳遞該參數,接口文檔中會對此特別說明,此時即使傳遞該參數也不會生效。

Timestamp

Integer

當前 UNIX 時間戳,可記錄發起 API 請求的時間。例如1529223702,如果與當前時間相差過大,會引起簽名過期錯誤。

Nonce

Integer

隨機正整數,與 Timestamp 聯合起來,用於防止重放攻擊。

SecretId

String

在 雲API密鑰 上申請的標識身份的 SecretId,一個 SecretId 對應唯一的 SecretKey,而 SecretKey 會用來生成請求籤名 Signature。

Signature

String

請求籤名,用來驗證此次請求的合法性,需要用戶根據實際的輸入參數計算得出。具體計算方法參見下文 「簽名方法介紹」 。

Version

String

操作的 API 的版本。取值參考接口文檔中入參公共參數 Version 的說明。例如雲伺服器的版本2017-03-12。

SignatureMethod

String

簽名方式,目前支持 HmacSHA256 和 HmacSHA1。只有指定此參數為 HmacSHA256 時,才使用 HmacSHA256 算法驗證簽名,其他情況均使用 HmacSHA1 驗證簽名。

Token

String

臨時證書所用的 Token ,需要結合臨時密鑰一起使用。臨時密鑰和 Token 需要到訪問管理服務調用接口獲取。長期密鑰不需要 Token 。

地域列表

由於各個產品支持地域不同,具體詳情請參考各產品文檔中的地域列表。
例如,您可以參考雲伺服器的 地域列表。

Java API 調用方式

騰訊雲 API 會對每個請求進行身份驗證,用戶需要使用安全憑證,經過特定的步驟對請求進行簽名(Signature),每個請求都需要在公共請求參數中指定該簽名結果並以指定的方式和格式發送請求。

假設用戶的 SecretId 和 SecretKey 分別是:AKIDz8krbsJ5**********mLPx3EXAMPLGu5t9xGAR***********EXAMPLE。用戶想查看廣州區雲伺服器名為「未命名」的主機狀態,只返回一條數據。則請求可能為:

curl -X POST https://cvm.tencentcloudapi.com \
-H "Authorization: TC3-HMAC-SHA256 Credential=AKIDz8krbsJ5**********mLPx3EXAMPL/2019-02-25/cvm/tc3_request, SignedHeaders=content-type;host, Signature=72e494ea8******************************************a96525168" \
-H "Content-Type: application/json; charset=utf-8" \
-H "Host: cvm.tencentcloudapi.com" \
-H "X-TC-Action: DescribeInstances" \
-H "X-TC-Timestamp: 1551113065" \
-H "X-TC-Version: 2017-03-12" \
-H "X-TC-Region: ap-guangzhou" \
-d '{"Limit": 1, "Filters": [{"Values": ["\u672a\u547d\u540d"], "Name": "instance-name"}]}'

步驟1:申請安全憑證

本文使用的安全憑證為密鑰,密鑰包括 SecretId 和 SecretKey。每個用戶最多可以擁有兩對密鑰。

  • SecretId:用於標識 API 調用者身份,可以簡單類比為用戶名。
  • SecretKey:用於驗證 API 調用者的身份,可以簡單類比為密碼。

注意

用戶必須嚴格保管安全憑證,避免泄露,否則將危及財產安全。如已泄漏,請立刻禁用該安全憑證。

前往 API密鑰管理 頁面,即可進行獲取。如下圖所示:

步驟2:

1. 獲取 API 3.0 V3 版本簽名

簽名方法 v3(TC3-HMAC-SHA256)功能上覆蓋了以前的簽名方法 v1 ,而且更安全,支持更大的請求,支持 json 格式,性能有一定提升,推薦使用該簽名方法計算簽名。

注意

首次接觸,建議使用 API Explorer 中的「簽名串生成」功能,選擇簽名版本為「 API 3.0 簽名 v3 」,可以生成簽名過程進行驗證,也可直接生成 SDK 代碼。推薦使用騰訊雲 API 配套的7種常見的程式語言 SDK,已經封裝了簽名和請求過程,均已開源,支持 Python、Java、PHP、Go、NodeJS、.NET、C++。

雲 API 支持 GET 和 POST 請求。對於 GET 方法,只支持 Content-Type: application/x-www-form-urlencoded 協議格式。對於 POST 方法,目前支持 Content-Type: application/json 以及 Content-Type: multipart/form-data 兩種協議格式,json 格式絕大多數接口均支持,multipart 格式只有特定接口支持,此時該接口不能使用 json 格式調用,參考具體業務接口文檔說明。推薦使用 POST 請求,因為兩者的結果並無差異,但 GET 請求只支持32KB以內的請求包。

下面以 查看實例列表 接口為例,分步驟介紹簽名的計算過程。我們選擇該接口是因為:

  1. 雲伺服器默認已開通,該接口很常用。
  2. 該接口是只讀的,不會改變現有資源的狀態。
  3. 接口覆蓋的參數種類較全,可以演示包含數據結構的數組如何使用。

1. 拼接規範請求串

CanonicalRequest =
    HTTPRequestMethod + '\n' +
    CanonicalURI + '\n' +
    CanonicalQueryString + '\n' +
    CanonicalHeaders + '\n' +
    SignedHeaders + '\n' +
    HashedRequestPayload

欄位名稱

解釋

HTTPRequestMethod

HTTP 請求方法(GET、POST )。此示例取值為 POST

CanonicalURI

URI 參數,API 3.0 固定為正斜槓(/)。

CanonicalQueryString

發起 HTTP 請求 URL 中的查詢字符串,對於 POST 請求,固定為空字符串"",對於 GET 請求,則為 URL 中問號(?)後面的字符串內容,例如:Limit=10&Offset=0。 注意:CanonicalQueryString 需要參考 RFC3986 進行 URLEncode,字符集 UTF8,推薦使用程式語言標準庫,所有特殊字符均需編碼,大寫形式。

CanonicalHeaders

參與簽名的頭部信息,至少包含 host 和 content-type 兩個頭部,也可加入自定義的頭部參與簽名以提高自身請求的唯一性和安全性。 拼接規則:頭部 key 和 value 統一轉成小寫,並去掉首尾空格,按照 key:value\n 格式拼接;多個頭部,按照頭部 key(小寫)的 ASCII 升序進行拼接。此示例計算結果是 content-type:application/json; charset=utf-8\nhost:cvm.tencentcloudapi.com\n。** 注意:content-type 必須和實際發送的相符合,有些程式語言網絡庫即使未指定也會自動添加 charset 值,如果簽名時和發送時不一致,伺服器會返回簽名校驗失敗。**

SignedHeaders

參與簽名的頭部信息,說明此次請求有哪些頭部參與了簽名,和 CanonicalHeaders 包含的頭部內容是一一對應的。content-type 和 host 為必選頭部。 拼接規則:頭部 key 統一轉成小寫;多個頭部 key(小寫)按照 ASCII 升序進行拼接,並且以分號(;)分隔。此示例為 content-type;host

HashedRequestPayload

請求正文(Requestpayload,即 body,此示例為 {"Limit": 1, "Filters": [{"Values": ["\u672a\u547d\u540d"], "Name": "instance-name"}]})的哈希值,計算偽代碼為 Lowercase(HexEncode(Hash.SHA256(RequestPayload))),即對 HTTP 請求正文做 SHA256 哈希,然後十六進位編碼,最後編碼串轉換成小寫字母。對於 GET 請求,RequestPayload 固定為空字符串。此示例計算結果是 35e9c5b0e3ae67532d3c9f17ead6c90222632e5b1ff7f6e89887f1398934f064

根據以上規則,示例中得到的規範請求串如下:

POST
/

content-type:application/json; charset=utf-8
host:cvm.tencentcloudapi.com

content-type;host
35e9c5b0e3ae67532d3c9f17ead6c90222632e5b1ff7f6e89887f1398934f064

2. 拼接待簽名字符串

按如下格式拼接待簽名字符串:

StringToSign =
    Algorithm + \n +
    RequestTimestamp + \n +
    CredentialScope + \n +
    HashedCanonicalRequest

欄位名稱

解釋

Algorithm

簽名算法,目前固定為 TC3-HMAC-SHA256

RequestTimestamp

請求時間戳,即請求頭部的公共參數 X-TC-Timestamp 取值,取當前時間 UNIX 時間戳,精確到秒。此示例取值為 1551113065

CredentialScope

憑證範圍,格式為 Date/service/tc3_request,包含日期、所請求的服務和終止字符串(tc3_request)。Date 為 UTC 標準時間的日期,取值需要和公共參數 X-TC-Timestamp 換算的 UTC 標準時間日期一致;service 為產品名,必須與調用的產品域名一致。此示例計算結果是 2019-02-25/cvm/tc3_request。

HashedCanonicalRequest

前述步驟拼接所得規範請求串的哈希值,計算偽代碼為 Lowercase(HexEncode(Hash.SHA256(CanonicalRequest)))。此示例計算結果是 5ffe6a04c0664d6b969fab9a13bdab201d63ee709638e2749d62a09ca18d7031

注意

Date 必須從時間戳 X-TC-Timestamp 計算得到,且時區為 UTC+0。如果加入系統本地時區信息,例如東八區,將導致白天和晚上調用成功,但是凌晨時調用必定失敗。假設時間戳為 1551113065,在東八區的時間是 2019-02-26 00:44:25,但是計算得到的 Date 取 UTC+0 的日期應為 2019-02-25,而不是 2019-02-26。Timestamp 必須是當前系統時間,且需確保系統時間和標準時間是同步的,如果相差超過五分鐘則必定失敗。如果長時間不和標準時間同步,可能導致運行一段時間後,請求必定失敗,返回簽名過期錯誤。

根據以上規則,示例中得到的待簽名字符串如下:

TC3-HMAC-SHA256
1551113065
2019-02-25/cvm/tc3_request
5ffe6a04c0664d6b969fab9a13bdab201d63ee709638e2749d62a09ca18d7031

3. 計算簽名(偽代碼)

SecretKey = "Gu5t9xGAR***********EXAMPLE"
byte[] secretDate = hmac256(("TC3" + SecretKey).getBytes(UTF8), date);
byte[] secretService = hmac256(secretDate, service);
byte[] secretSigning = hmac256(secretService, "tc3_request");
String signature = DatatypeConverter.printHexBinary(hmac256(secretSigning, stringToSign)).toLowerCase();
System.out.println(signature);

派生出的密鑰 SecretDateSecretServiceSecretSigning 是二進位的數據,可能包含不可列印字符,此處不展示中間結果。

欄位名稱

解釋

SecretKey

原始的 SecretKey,即 Gu5t9xGAR***********EXAMPLE

date

即 Credential 中的 Date 欄位信息。此示例取值為 2019-02-25

service

即 Credential 中的 Service 欄位信息。此示例取值為 cvm

此示例計算結果是 72e494ea8******************************************a96525168

4. 拼接 Authorization

按如下格式拼接 Authorization:

String Authorization =
    Algorithm + ' ' +
    'Credential=' + SecretId + '/' + CredentialScope + ', ' +
    'SignedHeaders=' + SignedHeaders + ', ' +
    'Signature=' + Signature

欄位名稱

解釋

Algorithm

簽名方法,固定為 TC3-HMAC-SHA256

SecretId

密鑰對中的 SecretId,即 AKIDz8krbsJ5**********mLPx3EXAMPL

CredentialScope

見上文,憑證範圍。此示例計算結果是 2019-02-25/cvm/tc3_request

SignedHeaders

見上文,參與簽名的頭部信息。此示例取值為 content-type;host

Signature

簽名值。此示例計算結果是 72e494ea8******************************************a96525168

根據以上規則,示例中得到的值為:

TC3-HMAC-SHA256 Credential=AKIDz8krbsJ5**********mLPx3EXAMPL/2019-02-25/cvm/tc3_request, SignedHeaders=content-type;host, Signature=72e494ea8******************************************a96525168

最終完整的調用信息如下:

POST https://cvm.tencentcloudapi.com/
Authorization: TC3-HMAC-SHA256 Credential=AKIDz8krbsJ5**********mLPx3EXAMPL/2019-02-25/cvm/tc3_request, SignedHeaders=content-type;host, Signature=72e494ea8******************************************a96525168
Content-Type: application/json; charset=utf-8
Host: cvm.tencentcloudapi.com
X-TC-Action: DescribeInstances
X-TC-Version: 2017-03-12
X-TC-Timestamp: 1551113065
X-TC-Region: ap-guangzhou

{"Limit": 1, "Filters": [{"Values": ["\u672a\u547d\u540d"], "Name": "instance-name"}]}

5. API 3.0 簽名 V3示例

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import java.util.TreeMap;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;

public class TencentCloudAPITC3Demo {
    private final static Charset UTF8 = StandardCharsets.UTF_8;
    private final static String SECRET_ID = "AKIDz8krbsJ5**********mLPx3EXAMPL";
    private final static String SECRET_KEY = "Gu5t9xGAR***********EXAMPLE";
    private final static String CT_JSON = "application/json; charset=utf-8";

    public static byte[] hmac256(byte[] key, String msg) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm());
        mac.init(secretKeySpec);
        return mac.doFinal(msg.getBytes(UTF8));
    }

    public static String sha256Hex(String s) throws Exception {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] d = md.digest(s.getBytes(UTF8));
        return DatatypeConverter.printHexBinary(d).toLowerCase();
    }

    public static void main(String[] args) throws Exception {
        String service = "cvm";
        String host = "cvm.tencentcloudapi.com";
        String region = "ap-guangzhou";
        String action = "DescribeInstances";
        String version = "2017-03-12";
        String algorithm = "TC3-HMAC-SHA256";
        String timestamp = "1551113065";
        //String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        // 注意時區,否則容易出錯
        sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
        String date = sdf.format(new Date(Long.valueOf(timestamp + "000")));

        // ************* 步驟 1:拼接規範請求串 *************
        String httpRequestMethod = "POST";
        String canonicalUri = "/";
        String canonicalQueryString = "";
        String canonicalHeaders = "content-type:application/json; charset=utf-8\n" + "host:" + host + "\n";
        String signedHeaders = "content-type;host";

        String payload = "{\"Limit\": 1, \"Filters\": [{\"Values\": [\"\\u672a\\u547d\\u540d\"], \"Name\": \"instance-name\"}]}";
        String hashedRequestPayload = sha256Hex(payload);
        String canonicalRequest = httpRequestMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n"
                + canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload;
        System.out.println(canonicalRequest);

        // ************* 步驟 2:拼接待簽名字符串 *************
        String credentialScope = date + "/" + service + "/" + "tc3_request";
        String hashedCanonicalRequest = sha256Hex(canonicalRequest);
        String stringToSign = algorithm + "\n" + timestamp + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
        System.out.println(stringToSign);

        // ************* 步驟 3:計算簽名 *************
        byte[] secretDate = hmac256(("TC3" + SECRET_KEY).getBytes(UTF8), date);
        byte[] secretService = hmac256(secretDate, service);
        byte[] secretSigning = hmac256(secretService, "tc3_request");
        String signature = DatatypeConverter.printHexBinary(hmac256(secretSigning, stringToSign)).toLowerCase();
        System.out.println(signature);

        // ************* 步驟 4:拼接 Authorization *************
        String authorization = algorithm + " " + "Credential=" + SECRET_ID + "/" + credentialScope + ", "
                + "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
        System.out.println(authorization);

        TreeMap<String, String> headers = new TreeMap<String, String>();
        headers.put("Authorization", authorization);
        headers.put("Content-Type", CT_JSON);
        headers.put("Host", host);
        headers.put("X-TC-Action", action);
        headers.put("X-TC-Timestamp", timestamp);
        headers.put("X-TC-Version", version);
        headers.put("X-TC-Region", region);

        StringBuilder sb = new StringBuilder();
        sb.append("curl -X POST https://").append(host)
        .append(" -H \"Authorization: ").append(authorization).append("\"")
        .append(" -H \"Content-Type: application/json; charset=utf-8\"")
        .append(" -H \"Host: ").append(host).append("\"")
        .append(" -H \"X-TC-Action: ").append(action).append("\"")
        .append(" -H \"X-TC-Timestamp: ").append(timestamp).append("\"")
        .append(" -H \"X-TC-Version: ").append(version).append("\"")
        .append(" -H \"X-TC-Region: ").append(region).append("\"")
        .append(" -d '").append(payload).append("'");
        System.out.println(sb.toString());
    }
}

2. 獲取 API 3.0 V1 版本簽名

簽名方法 v1 簡單易用,但是功能和安全性都不如簽名方法 v3,推薦使用簽名方法 v3。

注意

首次接觸,建議使用 API Explorer 中的「簽名串生成」功能,選擇簽名版本為「 API 3.0 簽名 v1 」,可以生成簽名過程進行驗證,並提供了部分程式語言的簽名示例,也可直接生成 SDK 代碼。推薦使用騰訊雲 API 配套的 7 種常見的程式語言 SDK,已經封裝了簽名和請求過程,均已開源,支持 Python、Java、PHP、Go、NodeJS、.NET、C++。

以雲伺服器查看實例列表(DescribeInstances)請求為例,當用戶調用這一接口時,其請求參數可能如下:

參數名稱

中文

參數值

Action

方法名

DescribeInstances

SecretId

密鑰 ID

AKIDz8krbsJ5**********mLPx3EXAMPL

Timestamp

當前時間戳

1465185768

Nonce

隨機正整數

11886

Region

實例所在區域

ap-guangzhou

InstanceIds.0

待查詢的實例 ID

ins-09dx96dg

Offset

偏移量

0

Limit

最大允許輸出

20

Version

接口版本號

2017-03-12

1. 對參數排序

首先對所有請求參數按參數名的字典序( ASCII 碼)升序排序。

注意

只按參數名進行排序,參數值保持對應即可,不參與比大小。按 ASCII 碼比大小,如 InstanceIds.2 要排在 InstanceIds.12 後面,不是按字母表,也不是按數值。用戶可以藉助程式語言中的相關排序函數來實現這一功能,如 PHP 中的 ksort 函數。

上述示例參數的排序結果如下:

{
    'Action' : 'DescribeInstances',
    'InstanceIds.0' : 'ins-09dx96dg',
    'Limit' : 20,
    'Nonce' : 11886,  
    'Offset' : 0,
    'Region' : 'ap-guangzhou',
    'SecretId' : 'AKIDz8krbsJ5**********mLPx3EXAMPL',
    'Timestamp' : 1465185768,
    'Version': '2017-03-12',
}

使用程序設計語言開發時,可對上面示例中的參數進行排序,得到的結果一致即可。

2. 拼接規範請求串

此步驟生成請求字符串。 將把上一步排序好的請求參數格式化成「參數名稱=參數值」的形式,如對 Action 參數,其參數名稱為 " Action " ,參數值為 " DescribeInstances " ,因此格式化後就為 Action=DescribeInstances 。

注意

「參數值」為原始值而非 url 編碼後的值。

然後將格式化後的各個參數用"&"拼接在一起,最終生成的請求字符串為:

Action=DescribeInstances&InstanceIds.0=ins-09dx96dg&Limit=20&Nonce=11886&Offset=0&Region=ap-guangzhou&SecretId=AKIDz8krbsJ5**********mLPx3EXAMPL&Timestamp=1465185768&Version=2017-03-12

3. 拼接待簽名字符串

此步驟生成簽名原文字符串。 簽名原文字符串由以下幾個參數構成:

  1. 請求方法:支持 POST 和 GET 方式,這裡使用 GET 請求,注意方法為全大寫。
  2. 請求主機:查看實例列表(DescribeInstances)的請求域名為 cvm.tencentcloudapi.com 。實際的請求域名根據接口所屬模塊的不同而不同,詳見各接口說明。
  3. 請求路徑:當前版本雲 API 的請求路徑固定為 /
  4. 請求字符串:即上一步生成的請求字符串。

簽名原文串的拼接規則為:請求方法 + 請求主機 +請求路徑 + ? + 請求字符串

示例的拼接結果為:

GETcvm.tencentcloudapi.com/?Action=DescribeInstances&InstanceIds.0=ins-09dx96dg&Limit=20&Nonce=11886&Offset=0&Region=ap-guangzhou&SecretId=AKIDz8krbsJ5**********mLPx3EXAMPL&Timestamp=1465185768&Version=2017-03-12

4. 計算簽名(偽代碼)

此步驟生成簽名串。 首先使用 HMAC-SHA1 算法對上一步中獲得的簽名原文字符串進行簽名,然後將生成的簽名串使用 Base64 進行編碼,即可獲得最終的簽名串。

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

/**
 *
 * [Hmac-SHA1 簽名算法]
 * @String  encryptText [加密字符源串]
 * @String  encryptKey  [加密密鑰]
 * @return [簽名值]
 */
public class HmacSHA1 {
    private static final String MAC_NAME = "HmacSHA1";
    public static final String ENCODING = "UTF-8";
    //簽名方法
    public static String HmacSHA1Encrypt(String s,String secret_key ) throws Exception{
        byte[] data = encryptKey.getBytes( ENCODING );
        SecretKey secretKey = new SecretKeySpec( data, MAC_NAME );
        Mac mac = Mac.getInstance( MAC_NAME );
        mac.init( secretKey );
        byte[] text = encryptText.getBytes( ENCODING );
        byte[] digest = mac.doFinal( text );
        return new String(Base64.encodeBase64(digest));
    }
}
String secret_key = "Gu5t9xGAR***********EXAMPLE";
String s = "GETcvm.tencentcloudapi.com/?Action=DescribeInstances&InstanceIds.0=ins-09dx96dg&Limit=20&Nonce=11886&Offset=0&Region=ap-guangzhou&SecretId=AKIDz8krbsJ5**********mLPx3EXAMPL&Timestamp=1465185768&Version=2017-03-12";
//最終簽名串
String Signature = new HmacSHA1();
System.out.println(Signature)

5. 獲取調用信息並發送請求

# 實際調用,成功後可能如果是消費接口會產生計費(此處以Python語言為例發送get請求)
resp = requests.get("https://" + endpoint, params=data)
print(resp.url)

最終得到的請求串為:

https://cvm.tencentcloudapi.com/?Action=DescribeInstances&InstanceIds.0=ins-09dx96dg&Limit=20&Nonce=11886&Offset=0&Region=ap-guangzhou&SecretId=AKIDz8krbsJ5**********mLPx3EXAMPL&Signature=EliP9YW3pW28FpsEdkXt%2F%2BWcGeI%3D&Timestamp=1465185768&Version=2017-03-12

欄位名稱

解釋

endpoint

服務地址, 例如:cvm.tencentcloudapi.com

data

API 3.0 簽名 V1 所舉示例接口參數,注意 這裡需要將計算的簽名已鍵值對的形式加入data中

注意

由於示例中的密鑰是虛構的,時間戳也不是系統當前時間,因此如果將此 url 在瀏覽器中打開或者用 curl 等命令調用時會返回鑒權錯誤:簽名過期。為了得到一個可以正常返回的 url ,需要修改示例中的 SecretId 和 SecretKey 為真實的密鑰,並使用系統當前時間戳作為 Timestamp。

為了更清楚的解釋簽名過程,下面以 Java 語言為例,將上述的簽名過程具體實現。請求的域名、調用的接口和參數的取值都以上述簽名過程為準,代碼只為解釋簽名過程,並不具備通用性,實際開發請儘量使用 SDK 。

6. 簽名串編碼

生成的簽名串並不能直接作為請求參數,需要對其進行 URL 編碼。

如上一步生成的簽名串為 Eli*****************cGeI= ,最終得到的簽名串請求參數(Signature)為:EliP***********************eI%3d,它將用於生成最終的請求 URL。

注意

如果用戶的請求方法是 GET,或者請求方法為 POST 同時 Content-Type 為 application/x-www-form-urlencoded,則發送請求時所有請求參數的值均需要做 URL 編碼,參數鍵和=符號不需要編碼。非 ASCII 字符在 URL 編碼前需要先以 UTF-8 進行編碼。有些程式語言的網絡庫會自動為所有參數進行 urlencode,在這種情況下,就不需要對簽名串進行 URL 編碼了,否則兩次 URL 編碼會導致簽名失敗。其他參數值也需要進行編碼,編碼採用 RFC 3986。使用 %XY 對特殊字符例如漢字進行百分比編碼,其中「 X 」和「 Y 」為十六進位字符(0-9 和大寫字母 A-F),使用小寫將引發錯誤。

7. API 3.0 簽名 V1示例

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Random;
import java.util.TreeMap;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;

public class TencentCloudAPIDemo {
    private final static String CHARSET = "UTF-8";

    public static String sign(String s, String key, String method) throws Exception {
        Mac mac = Mac.getInstance(method);
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(CHARSET), mac.getAlgorithm());
        mac.init(secretKeySpec);
        byte[] hash = mac.doFinal(s.getBytes(CHARSET));
        return DatatypeConverter.printBase64Binary(hash);
    }

    public static String getStringToSign(TreeMap<String, Object> params) {
        StringBuilder s2s = new StringBuilder("GETcvm.tencentcloudapi.com/?");
        // 簽名時要求對參數進行字典排序,此處用TreeMap保證順序
        for (String k : params.keySet()) {
            s2s.append(k).append("=").append(params.get(k).toString()).append("&");
        }
        return s2s.toString().substring(0, s2s.length() - 1);
    }

    public static String getUrl(TreeMap<String, Object> params) throws UnsupportedEncodingException {
        StringBuilder url = new StringBuilder("https://cvm.tencentcloudapi.com/?");
        // 實際請求的url中對參數順序沒有要求
        for (String k : params.keySet()) {
            // 需要對請求串進行urlencode,由於key都是英文字母,故此處僅對其value進行urlencode
            url.append(k).append("=").append(URLEncoder.encode(params.get(k).toString(), CHARSET)).append("&");
        }
        return url.toString().substring(0, url.length() - 1);
    }

    public static void main(String[] args) throws Exception {
        TreeMap<String, Object> params = new TreeMap<String, Object>(); // TreeMap可以自動排序
        // 實際調用時應當使用隨機數,例如:params.put("Nonce", new Random().nextInt(java.lang.Integer.MAX_VALUE));
        params.put("Nonce", 11886); // 公共參數
        // 實際調用時應當使用系統當前時間,例如:   params.put("Timestamp", System.currentTimeMillis() / 1000);
        params.put("Timestamp", 1465185768); // 公共參數
        params.put("SecretId", "AKIDz8krbsJ5**********mLPx3EXAMPL"); // 公共參數
        params.put("Action", "DescribeInstances"); // 公共參數
        params.put("Version", "2017-03-12"); // 公共參數
        params.put("Region", "ap-guangzhou"); // 公共參數
        params.put("Limit", 20); // 業務參數
        params.put("Offset", 0); // 業務參數
        params.put("InstanceIds.0", "ins-09dx96dg"); // 業務參數
        params.put("Signature", sign(getStringToSign(params), "Gu5t9xGAR***********EXAMPLE", "HmacSHA1")); // 公共參數
        System.out.println(getUrl(params));
    }
}

API 2.0 簽名

此簽名現已不在維護,建議使用性能更優的 API 3.0 簽名,如需使用,請直接在 API Explorer 的 簽名串生成 > 選擇 API 2.0 簽名版本進行操作。

簽名失敗

存在以下簽名失敗的錯誤碼,請根據實際情況處理。

錯誤碼

錯誤描述

AuthFailure.SignatureExpire

簽名過期。Timestamp 與伺服器接收到請求的時間相差不得超過五分鐘。

AuthFailure.SecretIdNotFound

密鑰不存在。請到控制台查看密鑰是否被禁用,是否少複製了字符或者多了字符。

AuthFailure.SignatureFailure

簽名錯誤。可能是簽名計算錯誤,或者簽名與實際發送的內容不相符合,也有可能是密鑰 SecretKey 錯誤導致的。

AuthFailure.TokenFailure

臨時證書 Token 錯誤。

AuthFailure.InvalidSecretId

密鑰非法(不是雲 API 密鑰類型)。

返回結果

正確返回結果

以雲伺服器的接口查看實例狀態列表( DescribeInstancesStatus )2017-03-12版本為例,若調用成功,其可能的返回如下為:

{
    "Response": {
        "TotalCount": 0,
        "InstanceStatusSet": [],
        "RequestId": "b5b41468-520d-4192-b42f-595cc34b6c1c"
    }
}
  • Response 及其內部的 RequestId 是固定的欄位,無論請求成功與否,只要 API 處理了,則必定會返回。
  • RequestId 用於一個 API 請求的唯一標識,如果 API 出現異常,可以聯繫我們,並提供該 ID 來解決問題。
  • 除了固定的欄位外,其餘均為具體接口定義的欄位,不同的接口所返回的欄位參見接口文檔中的定義。此例中的 TotalCountInstanceStatusSet 均為 DescribeInstancesStatus 接口定義的欄位,由於調用請求的用戶暫時還沒有雲伺服器實例,因此 TotalCount 在此情況下的返回值為 0, InstanceStatusSet 列表為空。

錯誤返回結果

若調用失敗,其返回值示例如下為:

{
    "Response": {
        "Error": {
            "Code": "AuthFailure.SignatureFailure",
            "Message": "The provided credentials could not be validated. Please check your signature is correct."
        },
        "RequestId": "ed93f3cb-f35e-473f-b9f3-0d451b8b79c6"
    }
}
  • Error 的出現代表著該請求調用失敗。Error 欄位連同其內部的 CodeMessage 欄位在調用失敗時是必定返回的。
  • Code 表示具體出錯的錯誤碼,當請求出錯時可以先根據該錯誤碼在公共錯誤碼和當前接口對應的錯誤碼列表裡面查找對應原因和解決方案。
  • Message 顯示出了這個錯誤發生的具體原因,隨著業務發展或體驗優化,此文本可能會經常保持變更或更新,用戶不應依賴這個返回值。
  • RequestId 用於一個 API 請求的唯一標識,如果 API 出現異常,可以聯繫我們,並提供該 ID 來解決問題。

公共錯誤碼

返回結果中如果存在 Error 欄位,則表示調用 API 接口失敗。 Error 中的 Code 欄位表示錯誤碼,所有業務都可能出現的錯誤碼為公共錯誤碼,下表列出了公共錯誤碼。


錯誤碼

錯誤描述

AuthFailure.InvalidSecretId

密鑰非法(不是雲 API 密鑰類型)。

AuthFailure.MFAFailure

MFA 錯誤。

AuthFailure.SecretIdNotFound

密鑰不存在。

AuthFailure.SignatureExpire

簽名過期。

AuthFailure.SignatureFailure

簽名錯誤。

AuthFailure.TokenFailure

token 錯誤。

AuthFailure.UnauthorizedOperation

請求未 CAM 授權。

DryRunOperation

DryRun 操作,代表請求將會是成功的,只是多傳了 DryRun 參數。

FailedOperation

操作失敗。

InternalError

內部錯誤。

InvalidAction

接口不存在。

InvalidParameter

參數錯誤。

InvalidParameterValue

參數取值錯誤。

LimitExceeded

超過配額限制。

MissingParameter

缺少參數錯誤。

NoSuchVersion

接口版本不存在。

RequestLimitExceeded

請求的次數超過了頻率限制。

ResourceInUse

資源被占用。

ResourceInsufficient

資源不足。

ResourceNotFound

資源不存在。

ResourceUnavailable

資源不可用。

UnauthorizedOperation

未授權操作。

UnknownParameter

未知參數錯誤。

UnsupportedOperation

操作不支持。

UnsupportedProtocol

HTTPS 請求方法錯誤,只支持 GET 和 POST 請求。

UnsupportedRegion

接口不支持所傳地域。

小夥伴們有興趣想了解內容和更多相關學習資料的請點讚收藏+評論轉發+關注我,後面會有很多乾貨。我有一些面試題、架構、設計類資料可以說是程式設計師面試必備!所有資料都整理到網盤了,需要的話歡迎下載!私信我回復【111】即可免費獲取
























































出處:https://cloud.tencent.com/document/product/1278/46713

關鍵字: