本文說明如何使用 C# 建立授權的 REST 要求,以呼叫 Azure 儲存體 REST API 作業。 瞭解如何呼叫 Blob 儲存體的 REST API 作業之後,您可以針對任何其他 Azure 儲存體 REST 作業使用類似的步驟。
先決條件
範例應用程式會列出儲存帳號中的 Blob 容器。 若要試用本文中的程式碼,您需要下列項目:
安裝 Visual Studio 並包含 Azure 開發 工作負載。 此範例是使用 Visual Studio 2019 建置。 如果您使用不同的版本,指引可能會略有不同。
Azure 訂用帳戶。 如尚未擁有 Azure 訂用帳戶,請在開始之前先建立免費帳戶。
一般用途儲存體帳戶。 如果您還沒有儲存體帳戶,請參閱 建立儲存體帳戶。
本文中的範例示範如何列出儲存體帳戶中的容器。 若要查看輸出,請先將一些 Blob 容器新增至儲存體帳戶,再開始。
下載範例應用程式
範例應用程式是以 C# 撰寫的主控台應用程式。
使用 git 將應用程式的複本下載至您的開發環境。
git clone https://github.com/Azure-Samples/storage-dotnet-rest-api-with-auth.git
此命令會將存放庫複製到本機 git 資料夾。 若要開啟 Visual Studio 解決方案,請流覽至 storage-dotnet-rest-api-with-auth 資料夾,然後開啟 StorageRestApiAuth.sln。
關於 REST
具象狀態傳輸 (REST) 是一種架構,可讓您透過網際網路通訊協定 (例如 HTTP/HTTPS) 與服務互動。 REST 獨立於伺服器或用戶端上執行的軟體。 REST API 可以從任何支援 HTTP/HTTPS 的平台呼叫。 您可以撰寫在 Mac、Windows、Linux、Android 手機或平板電腦、iPhone、iPod 或網站上執行的應用程式,並為所有這些平台使用相同的 REST API。
對 REST API 的呼叫包含用戶端發出的要求,以及服務所傳回的回應。 在要求中,您會傳送一個 URL,其中包含關於您想要呼叫的作業、要處理的資源、任何查詢參數和標頭,以及資料的承載 (視呼叫的作業而定) 的資訊。 來自服務的回應包括狀態碼、一組回應標頭,以及視呼叫的操作而定,還有資料負載。
關於範例應用程式
範例應用程式會列出儲存體帳戶中的容器。 一旦您了解 REST API 文檔中的信息如何與您的實際代碼相關聯,其他 REST 調用就更容易弄清楚。
如果您查看 Blob 服務 REST API,您會看到您可以在 Blob 儲存體上執行的所有作業。 儲存用戶端程式庫是 REST API 的包裝函式,可讓您輕鬆存取儲存資源,而無需直接使用 REST API。 不過,有時您可能想要使用 REST API 而不是儲存用戶端程式庫。
列出容器作業
本文著重於 列出容器 作業。 下列資訊可協助您瞭解要求和回應中的某些欄位。
請求方式:GET。 此動詞是您指定為請求物件屬性的 HTTP 方法。 此動詞的其他值包括 HEAD、PUT 和 DELETE,視您呼叫的 API 而定。
請求 URI:https://myaccount.blob.core.windows.net/?comp=list 。 要求 URI 是從 Blob 儲存體帳戶端點 https://myaccount.blob.core.windows.net 和資源字串 /?comp=list建立。
URI 參數:呼叫 ListContainers 時可以使用其他查詢參數。 其中有幾個參數是呼叫的 timeout (以秒為單位) 以及用於篩選的 prefix。
另一個有用的參數是 maxresults:如果可用的容器數量超過此值,則回應本文將包含一個 NextMarker 元素,該元素指示下一個容器在下一個請求中返回。 若要使用此功能,請在提出下一個要求時,在 URI 中提供 NextMarker 值作為 標記 參數。 使用此功能時,類似於逐頁瀏覽結果。
若要使用其他參數,請將它們附加到具有值的資源字串中,例如以下範例:
/?comp=list&timeout=60&maxresults=100
請求標頭: 本節列出了必要和可選的請求標頭。 需要三個標頭: 授權 標頭、 x-ms-date (包含要求的 UTC 時間) 和 x-ms-version (指定要使用的 REST API 版本)。 在標頭中包含 x-ms-client-request-id 是選擇性的。 您可以將此欄位的值設定為任何值,並在啟用記錄時將其寫入儲存體分析記錄。
要求主體:ListContainers 沒有要求主體。 上傳 Blob 時,所有 PUT 作業都會使用請求主體,包括 SetContainerAccessPolicy。 「要求內文」可讓您傳送要套用的已儲存存取原則的 XML 清單。 使用 共用存取簽章 (SAS) 一文會討論預存的存取原則。
回應狀態碼: 告知您需要知道的任何狀態碼。 在此範例中,HTTP 狀態碼 200 是可以的。 如需 HTTP 狀態碼的完整清單,請參閱狀態 碼定義。 若要查看儲存體 REST API 特定的錯誤碼,請參閱 常見的 REST API 錯誤碼
回應標頭: 這些包括 內容類型; x-ms-request-id,這是您傳入的要求標識碼; x-ms-version,表示所使用的 Blob 服務版本;以及 Date,以 UTC 表示提出請求的時間。
回應內文:此欄位是提供所要求資料的 XML 結構。 在此範例中,回應是容器及其屬性的清單。
建立 REST 要求
為了在生產環境中執行時的安全性,請始終使用 HTTPS 而不是 HTTP。 基於本練習的目的,我們使用 HTTP,以便您可以檢視要求和回應資料。 若要檢視實際 REST 呼叫中的要求和回應資訊,您可以下載 Fiddler 或類似的應用程式。 在 Visual Studio 解決方案中,儲存體帳戶名稱和金鑰會硬式編碼在類別中。 ListContainersAsyncREST 方法會將儲存體帳戶名稱和儲存體帳戶金鑰傳遞至用來建立 REST 要求各種元件的方法。 在實際應用程式中,儲存體帳戶名稱和金鑰會位於組態檔、環境變數中,或從 Azure 金鑰保存庫擷取。
在我們的範例專案中,建立 Authorization 標頭的程式碼位於個別類別中。 這個想法是,您可以將整個課程添加到您自己的解決方案中,並“按原樣”使用它。授權標頭程式碼適用於大部分 REST API 呼叫 Azure 儲存體。
若要建置要求 (即 HttpRequestMessage 物件),請移至 Program.cs 中的 ListContainersAsyncREST。 建置請求的步驟如下:
- 建立要用來呼叫服務的 URI。
- 建立 HttpRequestMessage 物件並設定承載。 ListContainersAsyncREST 的承載為 Null,因為我們不會傳入任何內容。
- 新增 x-ms-date 和 x-ms-version 的要求標頭。
- 取得授權標頭並新增它。
您需要的一些基本資訊:
- 對於 ListContainers,方法是
GET。 此值是在實例化要求時設定。 -
資源是 URI 的查詢部分,指出正在呼叫哪個 API,因此值為
/?comp=list。 如先前所述,資源位於參考文件頁面上,其中顯示 ListContainers API 的相關資訊。 - URI 是藉由建立該儲存體帳戶的 Blob 服務端點並串連資源來建構。
要求 URI 的值最終為
http://contosorest.blob.core.windows.net/?comp=list。 - 對於 ListContainers,requestBody 為 null,且沒有額外的 標頭。
不同的 API 可能有其他參數要傳入,例如 ifMatch。 您可以使用 ifMatch 的範例是呼叫 PutBlob 時。 在此情況下,您可以將 ifMatch 設定為 eTag,並且只有在您提供的 eTag 與 Blob 上的目前 eTag 相符時,它才會更新 Blob。 如果有其他人在擷取 eTag 後更新 blob,將不會覆寫其變更。
首先,將 uri 和 requestPayload 設定。
// Construct the URI. It will look like this:
// https://myaccount.blob.core.windows.net/resource
String uri = string.Format("http://{0}.blob.core.windows.net?comp=list", storageAccountName);
// Provide the appropriate payload, in this case null.
// we're not passing anything in.
Byte[] requestPayload = null;
接下來,實例化請求,將方法設定為並提供 GET URI。
// Instantiate the request message with a null payload.
using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, uri)
{ Content = (requestPayload == null) ? null : new ByteArrayContent(requestPayload) })
{
新增 x-ms-date 和 x-ms-version 的要求標頭。 程式碼中的這個位置也就是您新增呼叫所需之任何其他要求標頭的位置。 在此範例中,沒有其他標頭。 傳入額外標頭的 API 範例是設定容器 ACL 作業。 此 API 呼叫會新增名為 「x-ms-blob-public-access」 的標頭,以及存取層級的值。
// Add the request headers for x-ms-date and x-ms-version.
DateTime now = DateTime.UtcNow;
httpRequestMessage.Headers.Add("x-ms-date", now.ToString("R", CultureInfo.InvariantCulture));
httpRequestMessage.Headers.Add("x-ms-version", "2017-07-29");
// If you need any additional headers, add them here before creating
// the authorization header.
呼叫建立授權標頭的方法,並將它新增至要求標頭。 授權標頭會在本文稍後建立。 方法名稱是 GetAuthorizationHeader,您可以在以下程式碼片段中看到:
// Get the authorization header and add it.
httpRequestMessage.Headers.Authorization = AzureStorageAuthenticationHelper.GetAuthorizationHeader(
storageAccountName, storageAccountKey, now, httpRequestMessage);
此時,httpRequestMessage 包含完整的 REST 請求和授權標頭。
發送請求
現在您已建構要求,您可以呼叫 SendAsync 方法,將它傳送至 Azure 儲存體。 檢查回應狀態碼的值是否為 200,表示作業已成功。 接下來,剖析回應。 在此情況下,您會取得容器的 XML 清單。 讓我們看看呼叫 GetRESTRequest 方法來建立請求、執行請求,然後檢查容器清單的回應的程式碼。
// Send the request.
using (HttpResponseMessage httpResponseMessage =
await new HttpClient().SendAsync(httpRequestMessage, cancellationToken))
{
// If successful (status code = 200),
// parse the XML response for the container names.
if (httpResponseMessage.StatusCode == HttpStatusCode.OK)
{
String xmlString = await httpResponseMessage.Content.ReadAsStringAsync();
XElement x = XElement.Parse(xmlString);
foreach (XElement container in x.Element("Containers").Elements("Container"))
{
Console.WriteLine("Container name = {0}", container.Element("Name").Value);
}
}
}
}
如果您在使用 Fiddler 等網路封包分析工具時,呼叫 SendAsync,您可以看到要求和回應的資訊。 讓我們一起來看看吧。 儲存體帳戶的名稱是 contosorest。
要求:
GET /?comp=list HTTP/1.1
請求標頭:
x-ms-date: Thu, 16 Nov 2017 23:34:04 GMT
x-ms-version: 2014-02-14
Authorization: SharedKey contosorest:1dVlYJWWJAOSHTCPGiwdX1rOS8B4fenYP/VrU0LfzQk=
Host: contosorest.blob.core.windows.net
Connection: Keep-Alive
執行後傳回的狀態碼和回應頭:
HTTP/1.1 200 OK
Content-Type: application/xml
Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: 3e889876-001e-0039-6a3a-5f4396000000
x-ms-version: 2017-07-29
Date: Fri, 17 Nov 2017 00:23:42 GMT
Content-Length: 1511
回應內文 (XML): 對於「列出容器」作業,這會顯示容器及其屬性的清單。
<?xml version="1.0" encoding="utf-8"?>
<EnumerationResults
ServiceEndpoint="http://contosorest.blob.core.windows.net/">
<Containers>
<Container>
<Name>container-1</Name>
<Properties>
<Last-Modified>Thu, 16 Mar 2017 22:39:48 GMT</Last-Modified>
<Etag>"0x8D46CBD5A7C301D"</Etag>
<LeaseStatus>unlocked</LeaseStatus>
<LeaseState>available</LeaseState>
</Properties>
</Container>
<Container>
<Name>container-2</Name>
<Properties>
<Last-Modified>Thu, 16 Mar 2017 22:40:50 GMT</Last-Modified>
<Etag>"0x8D46CBD7F49E9BD"</Etag>
<LeaseStatus>unlocked</LeaseStatus>
<LeaseState>available</LeaseState>
</Properties>
</Container>
<Container>
<Name>container-3</Name>
<Properties>
<Last-Modified>Thu, 16 Mar 2017 22:41:10 GMT</Last-Modified>
<Etag>"0x8D46CBD8B243D68"</Etag>
<LeaseStatus>unlocked</LeaseStatus>
<LeaseState>available</LeaseState>
</Properties>
</Container>
<Container>
<Name>container-4</Name>
<Properties>
<Last-Modified>Thu, 16 Mar 2017 22:41:25 GMT</Last-Modified>
<Etag>"0x8D46CBD93FED46F"</Etag>
<LeaseStatus>unlocked</LeaseStatus>
<LeaseState>available</LeaseState>
</Properties>
</Container>
<Container>
<Name>container-5</Name>
<Properties>
<Last-Modified>Thu, 16 Mar 2017 22:41:39 GMT</Last-Modified>
<Etag>"0x8D46CBD9C762815"</Etag>
<LeaseStatus>unlocked</LeaseStatus>
<LeaseState>available</LeaseState>
</Properties>
</Container>
</Containers>
<NextMarker />
</EnumerationResults>
現在您已經瞭解如何建立請求、呼叫服務以及剖析結果,讓我們看看如何建立授權標頭。
建立授權標頭
小提示
Azure 儲存體支援與 Microsoft Entra 結合的 Blob 和佇列整合功能。 Microsoft Entra ID 提供更簡單的體驗來授權對 Azure 儲存體的要求。 如需使用 Microsoft Entra ID 授權 REST 作業的詳細資訊,請參閱 使用 Microsoft Entra ID 授權。 如需 Microsoft Entra 與 Azure 儲存體整合的概觀,請參閱 使用 Microsoft Entra ID 驗證 Azure 儲存體的存取權。
若要深入瞭解授權概念,請參閱 授權 Azure 儲存體的要求。
讓我們將這篇文章提煉為確切需要並顯示代碼。
首先,使用共用金鑰授權。 授權標頭格式如下所示:
Authorization="SharedKey <storage account name>:<signature>"
簽章欄位是根據請求建立並使用 SHA256 演算法計算的雜湊型訊息驗證碼 (HMAC),然後使用 Base64 編碼進行編碼。
此程式碼片段顯示共用金鑰簽章字串的格式:
StringToSign = VERB + "\n" +
Content-Encoding + "\n" +
Content-Language + "\n" +
Content-Length + "\n" +
Content-MD5 + "\n" +
Content-Type + "\n" +
Date + "\n" +
If-Modified-Since + "\n" +
If-Match + "\n" +
If-None-Match + "\n" +
If-Unmodified-Since + "\n" +
Range + "\n" +
CanonicalizedHeaders +
CanonicalizedResource;
針對 Blob 儲存體,您可以指定 VERB、MD5、內容長度、標準化標頭和標準化資源。 在此範例中,您可以將其他項目保留空白,但 放入 \n 以指定它們為空白。
規範化是標準化具有多個可能表示法的資料的程式。 在此情況下,您要標準化標頭和資源。 標準化的標頭是以「x-ms-」開頭的標頭。 正規化資源是資源的 URI,包括儲存體帳戶名稱和所有查詢參數 (例如 ?comp=list)。 規範化資源也包含您可能已新增的任何其他查詢參數,例如 timeout=60。
讓我們從兩個標準化欄位開始,因為它們是建立 Authorization 標頭所必需的。
規範化標頭
若要建立此值,請擷取以 “x-ms-” 開頭的標頭並排序它們,然後將它們格式化為實例字 [key:value\n] 串,串連成一個字串。 在此範例中,規範化標頭如下所示:
x-ms-date:Fri, 17 Nov 2017 00:44:48 GMT\nx-ms-version:2017-07-29\n
以下是用於建立該輸出的程式碼:
private static string GetCanonicalizedHeaders(HttpRequestMessage httpRequestMessage)
{
var headers = from kvp in httpRequestMessage.Headers
where kvp.Key.StartsWith("x-ms-", StringComparison.OrdinalIgnoreCase)
orderby kvp.Key
select new { Key = kvp.Key.ToLowerInvariant(), kvp.Value };
StringBuilder headersBuilder = new StringBuilder();
foreach (var kvp in headers)
{
headersBuilder.Append(kvp.Key);
char separator = ':';
// Get the value for each header, strip out \r\n if found, then append it with the key.
foreach (string headerValue in kvp.Value)
{
string trimmedValue = headerValue.TrimStart().Replace("\r\n", string.Empty);
headersBuilder.Append(separator).Append(trimmedValue);
// Set this to a comma; this will only be used
// if there are multiple values for one of the headers.
separator = ',';
}
headersBuilder.Append("\n");
}
return headersBuilder.ToString();
}
標準化資源
簽章字串的這一部分代表要求所針對的儲存體帳戶。 請記住,請求 URI 是 http://contosorest.blob.core.windows.net/?comp=list,具有實際帳戶名稱 (contosorest 在本例中為 )。 在此範例中,會傳回以下內容:
/contosorest/\ncomp:list
如果您有查詢參數,此範例也會包含這些參數。 這是程式碼,它也會處理其他查詢參數以及具有多個值的查詢參數。 請記住,您正在建置此程式碼以適用於所有 REST API。 您想要包含所有可能性,即使 ListContainers 方法不需要所有可能性也一樣。
private static string GetCanonicalizedResource(Uri address, string storageAccountName)
{
// The absolute path will be "/" because for we're getting a list of containers.
StringBuilder sb = new StringBuilder("/").Append(storageAccountName).Append(address.AbsolutePath);
// Address.Query is the resource, such as "?comp=list".
// This ends up with a NameValueCollection with 1 entry having key=comp, value=list.
// It will have more entries if you have more query parameters.
NameValueCollection values = HttpUtility.ParseQueryString(address.Query);
foreach (var item in values.AllKeys.OrderBy(k => k))
{
sb.Append('\n').Append(item.ToLower()).Append(':').Append(values[item]);
}
return sb.ToString();
}
現在已設定規範字串,讓我們看看如何建立授權標頭本身。 您可以先以本文先前顯示的 StringToSign 格式建立訊息簽章字串。 這個概念更容易在程式碼中使用註解來解釋,所以這是傳回 Authorization Header 的最後一個方法:
internal static AuthenticationHeaderValue GetAuthorizationHeader(
string storageAccountName, string storageAccountKey, DateTime now,
HttpRequestMessage httpRequestMessage, string ifMatch = "", string md5 = "")
{
// This is the raw representation of the message signature.
HttpMethod method = httpRequestMessage.Method;
String MessageSignature = String.Format("{0}\n\n\n{1}\n{5}\n\n\n\n{2}\n\n\n\n{3}{4}",
method.ToString(),
(method == HttpMethod.Get || method == HttpMethod.Head) ? String.Empty
: httpRequestMessage.Content.Headers.ContentLength.ToString(),
ifMatch,
GetCanonicalizedHeaders(httpRequestMessage),
GetCanonicalizedResource(httpRequestMessage.RequestUri, storageAccountName),
md5);
// Now turn it into a byte array.
byte[] SignatureBytes = Encoding.UTF8.GetBytes(MessageSignature);
// Create the HMACSHA256 version of the storage key.
HMACSHA256 SHA256 = new HMACSHA256(Convert.FromBase64String(storageAccountKey));
// Compute the hash of the SignatureBytes and convert it to a base64 string.
string signature = Convert.ToBase64String(SHA256.ComputeHash(SignatureBytes));
// This is the actual header that will be added to the list of request headers.
AuthenticationHeaderValue authHV = new AuthenticationHeaderValue("SharedKey",
storageAccountName + ":" + signature);
return authHV;
}
當您執行此程式碼時,產生的 MessageSignature 看起來像這樣的範例:
GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:Fri, 17 Nov 2017 01:07:37 GMT\nx-ms-version:2017-07-29\n/contosorest/\ncomp:list
以下是 AuthorizationHeader 的最終值:
SharedKey contosorest:Ms5sfwkA8nqTRw7Uury4MPHqM6Rj2nfgbYNvUKOa67w=
AuthorizationHeader 是在張貼回應之前放置在請求標頭中的最後一個標頭。
這涵蓋了您需要知道的所有內容,以將類別放在一起,您可以使用該類別建立呼叫儲存體服務 REST API 的要求。
範例:列出 Blob
讓我們看看如何變更程式碼以呼叫容器 container-1 的 List Blobs 作業。 此程式碼與列出容器的程式碼幾乎相同,唯一的差異是 URI 和剖析回應的方式。
如果您查看 ListBlobs 的參考檔,您會發現方法是 GET ,而 RequestURI 是:
https://myaccount.blob.core.windows.net/container-1?restype=container&comp=list
在 ListContainersAsyncREST 中,變更將 URI 設定為 ListBlobs API 的程式碼。 容器名稱為 container-1。
String uri =
string.Format("http://{0}.blob.core.windows.net/container-1?restype=container&comp=list",
storageAccountName);
然後,當您處理回應時,將程式碼修改為尋找 Blob 物件,而不是容器。
foreach (XElement container in x.Element("Blobs").Elements("Blob"))
{
Console.WriteLine("Blob name = {0}", container.Element("Name").Value);
}
當您執行此範例時,您會得到如下所示的結果:
規範化標頭:
x-ms-date:Fri, 17 Nov 2017 05:16:48 GMT\nx-ms-version:2017-07-29\n
規範化資源:
/contosorest/container-1\ncomp:list\nrestype:container
訊息簽名:
GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:Fri, 17 Nov 2017 05:16:48 GMT
\nx-ms-version:2017-07-29\n/contosorest/container-1\ncomp:list\nrestype:container
授權標頭:
SharedKey contosorest:uzvWZN1WUIv2LYC6e3En10/7EIQJ5X9KtFQqrZkxi6s=
下列值來自 Fiddler:
要求:
GET http://contosorest.blob.core.windows.net/container-1?restype=container&comp=list HTTP/1.1
請求標頭:
x-ms-date: Fri, 17 Nov 2017 05:16:48 GMT
x-ms-version: 2017-07-29
Authorization: SharedKey contosorest:uzvWZN1WUIv2LYC6e3En10/7EIQJ5X9KtFQqrZkxi6s=
Host: contosorest.blob.core.windows.net
Connection: Keep-Alive
執行後傳回的狀態碼和回應頭:
HTTP/1.1 200 OK
Content-Type: application/xml
Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: 7e9316da-001e-0037-4063-5faf9d000000
x-ms-version: 2017-07-29
Date: Fri, 17 Nov 2017 05:20:21 GMT
Content-Length: 1135
回應內文 (XML): 此 XML 回應會顯示 Blob 及其屬性的清單。
<?xml version="1.0" encoding="utf-8"?>
<EnumerationResults
ServiceEndpoint="http://contosorest.blob.core.windows.net/" ContainerName="container-1">
<Blobs>
<Blob>
<Name>DogInCatTree.png</Name>
<Properties><Last-Modified>Fri, 17 Nov 2017 01:41:14 GMT</Last-Modified>
<Etag>0x8D52D5C4A4C96B0</Etag>
<Content-Length>419416</Content-Length>
<Content-Type>image/png</Content-Type>
<Content-Encoding />
<Content-Language />
<Content-MD5 />
<Cache-Control />
<Content-Disposition />
<BlobType>BlockBlob</BlobType>
<LeaseStatus>unlocked</LeaseStatus>
<LeaseState>available</LeaseState>
<ServerEncrypted>true</ServerEncrypted>
</Properties>
</Blob>
<Blob>
<Name>GuyEyeingOreos.png</Name>
<Properties>
<Last-Modified>Fri, 17 Nov 2017 01:41:14 GMT</Last-Modified>
<Etag>0x8D52D5C4A25A6F6</Etag>
<Content-Length>167464</Content-Length>
<Content-Type>image/png</Content-Type>
<Content-Encoding />
<Content-Language />
<Content-MD5 />
<Cache-Control />
<Content-Disposition />
<BlobType>BlockBlob</BlobType>
<LeaseStatus>unlocked</LeaseStatus>
<LeaseState>available</LeaseState>
<ServerEncrypted>true</ServerEncrypted>
</Properties>
</Blob>
</Blobs>
<NextMarker />
</EnumerationResults>
總結
在本文中,您已瞭解如何向 Blob 儲存體 REST API 提出要求。 透過要求,您可以擷取容器清單或容器中的 Blob 清單。 您已瞭解如何建立 REST API 呼叫的授權簽章,以及如何在 REST 要求中使用它。 最後,您學會瞭如何檢查響應。