您通过 HTTP 请求来调用火山引擎私网解析(PrivateZone)的 API。
在发送 HTTP 请求前,您需要理解以下内容:
API 请求的结构包含以下内容:
私网解析 PrivateZone 的 API 服务域名是 private-zone.volcengineapi.com。
您可以使用 HTTP 协议或 HTTPS 协议发送请求。推荐您使用 HTTPS 协议,其安全性更高。
关于 API 所使用的方法,参见每个 API 的说明。对于 POST 请求,您必须在请求头中指定 Content-Type: application/json。
请求参数包括公共参数和每个 API 所特有的参数。
公共参数是每个 API 请求必须包含的参数。如果一个 API 请求缺失公共参数,请求会失败。以下表格中的公共参数必须包含在查询字符串(query string)中。
| 参数名称 | 数据类型 | 是否必选 | 说明 | 示例 |
|---|---|---|---|---|
| Action | string | 是 | 表示 API 名称。格式为 [a-zA-Z]+。 |
CreatePrivateZone |
| Version | string | 是 | 表示 API 版本。该参数的取值是 2022-06-01。 |
2022-06-01 |
| X-Expires | Integer | 否 | 签名的有效时间,单位为秒。默认值为 900。 | 900 |
每个请求中必须包含鉴权信息。该鉴权信息用以验证请求者的身份。
下面的示例代码演示了如何基于 Java 在调用 UpdatePrivateZone API 和 ListPrivateZones API 时对请求进行鉴权。
在运行示例代码之前,您需要 获取 Access Key ID 和 Secret Access Key。然后,您需要分别将 Access Key ID 和 Secret Access Key 的值传入示例代码中的 AK 常量和 SK 常量。
package com.volcengine.privatezone;
import com.alibaba.fastjson.JSON;
import org.apache.commons.codec.binary.Hex;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
public class MainDNS {
// 第一步:准备需要用到的类定义。
// 签算请求结构类
public static class RequestParam {
public final byte[] body;
public final String method;
public final Date date;
public final String path;
public final String host;
public final String contentType;
public final ArrayList<NameValuePair> queryList;
public RequestParam(byte[] body, String method, Date date, String path, String host, String contentType, ArrayList<NameValuePair> queryList) {
this.body = body;
this.method = method;
this.date = date;
this.path = path;
this.host = host;
this.contentType = contentType;
this.queryList = queryList;
}
}
public static final String TIME_FORMAT_V4 = "yyyyMMdd'T'HHmmss'Z'";
private static final TimeZone tz = TimeZone.getTimeZone("UTC");
// 分别将 Access Key ID 和 Secret Access Key 的值传入 AK 常量和 SK 常量
private static final String AK = "ak";
private static final String SK = "sk";
private static final String Service = "private_zone";
private static final String Version = "2022-06-01";
private static final String Region = "cn-north-1";
private static final String Host = "private-zone.volcengineapi.com";
// 第二步:准备辅助函数。
// sha256非对称加密
public static byte[] hmacSHA256(byte[] key, String content) {
try {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(key, "HmacSHA256"));
return mac.doFinal(content.getBytes());
} catch (Exception e) {
return null;
}
}
// sha256 hash算法
public static String hashSHA256(byte[] content) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
return Hex.encodeHexString(md.digest(content));
} catch (Exception e) {
return null;
}
}
private static String getAppointFormatDate(Date date) {
DateFormat df = new SimpleDateFormat(TIME_FORMAT_V4);
df.setTimeZone(tz);
return df.format(date);
}
// 第三步:创建一个 API 请求函数。签名计算的过程包含在该函数中。
public static byte[] request(String method, HashMap<String, String> query, HashMap<String, String> header, String ak, String sk, String action, byte[] body) throws URISyntaxException {
// 第四步:创建身份证明。其中的 Service 和 Region 字段是固定的。ak 和 sk 分别代表 AccessKeyID 和
// SecretAccessKey。
// 同时需要初始化签名对象。一些签名计算时需要的属性也在这里处理。
// 初始化身份证明
HashMap<String, String> credential = new HashMap() {
{
put("accessKeyId", ak);
put("secretKeyId", sk);
put("service", Service);
put("region", Region);
}
};
ArrayList<NameValuePair> nvps = new ArrayList<>();
for (Map.Entry<String, String> entry : query.entrySet()) {
nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
nvps.add(new BasicNameValuePair("Action", action));
nvps.add(new BasicNameValuePair("Version", Version));
Collections.sort(nvps, new Comparator<NameValuePair>() {
@Override
public int compare(NameValuePair o1, NameValuePair o2) {
return o1.getName().compareTo(o2.getName());
}
});
// 初始化签名结构
RequestParam requestParam = new RequestParam(body, method, new Date(), "/", Host, "application/json", nvps);
URI uri = new URIBuilder().addParameters(requestParam.queryList).build();
// 第五步:接下来开始计算签名
// 初始化签名结果变量
String xDate = getAppointFormatDate(new Date());
String shortXDate = xDate.substring(0, 8);
String xContentSha256 = hashSHA256(body);
// 第六步:计算签名
String[] headStr = {"content-type", "host", "x-content-sha256", "x-date"};
String signedHeadersStr = String.join(";", headStr);
String[] headStrSecond = {"content-type:" + requestParam.contentType, "host:" + requestParam.host, "x-content-sha256:" + xContentSha256, "x-date:" + xDate};
String preRequestStr = String.join("\n", headStrSecond);
String[] preCanonicalRequestStr = {requestParam.method, requestParam.path, uri.getRawQuery(), preRequestStr, "", signedHeadersStr, xContentSha256};
String canonicalRequestStr = String.join("\n", preCanonicalRequestStr);
String hashedCanonicalRequest = hashSHA256(canonicalRequestStr.getBytes());
String[] credentialStr = {shortXDate, credential.get("region"), credential.get("service"), "request"};
String credentialScope = String.join("/", credentialStr);
String[] preStringToSign = {"HMAC-SHA256", xDate, credentialScope, hashedCanonicalRequest};
String stringToSign = String.join("\n", preStringToSign);
byte[] kDate = hmacSHA256(credential.get("secretKeyId").getBytes(), shortXDate);
byte[] kRegion = hmacSHA256(kDate, credential.get("region"));
byte[] kService = hmacSHA256(kRegion, credential.get("service"));
byte[] kSigning = hmacSHA256(kService, "request");
String signature = Hex.encodeHexString(hmacSHA256(kSigning, stringToSign));
String authorization = String.format("HMAC-SHA256 Credential=%s, SignedHeaders=%s, Signature=%s", credential.get("accessKeyId") + "/" + credentialScope, signedHeadersStr, signature);
// 第七步,在request中,创建一个 HTTP 请求实例。
HttpUriRequest request;
if("POST".equalsIgnoreCase(method)){
HttpPost httpPost = new HttpPost("https://" + requestParam.host + requestParam.path + "?" + uri.getRawQuery());
// 第八步:将 Signature 签名写入HTTP Header 中,并发送 HTTP 请求。
// 设置经过签名的5个HTTP Header
httpPost.setEntity(new ByteArrayEntity(body));
for (Map.Entry<String, String> entry : header.entrySet()) {
httpPost.setHeader(entry.getKey(), entry.getValue());
}
request = httpPost;
} else if("GET".equalsIgnoreCase(method)){
HttpGet httpGet = new HttpGet("https://" + requestParam.host + requestParam.path + "?" + uri.getRawQuery());
for (Map.Entry<String, String> entry : header.entrySet()) {
httpGet.setHeader(entry.getKey(), entry.getValue());
}
request = httpGet;
} else {
throw new UnsupportedOperationException();
}
request.setHeader("Host", requestParam.host);
request.setHeader("Content-Type", requestParam.contentType);
request.setHeader("X-Date", xDate);
request.setHeader("X-Content-Sha256", xContentSha256);
request.setHeader("Authorization", authorization);
CloseableHttpClient httpClient = HttpClients.createDefault();
byte[] responseBody = null;
// 发送 HTTP 请求。
try {
CloseableHttpResponse response = httpClient.execute(request);
HttpEntity entity = response.getEntity();
responseBody = EntityUtils.toByteArray(entity);
EntityUtils.consume(entity);
} catch (IOException e) {
e.printStackTrace();
}
return responseBody;
}
public static void main(String[] args) throws URISyntaxException {
//(POST 请求)调用 UpdatePrivateZone API
HashMap<String, Object> requestBody = new HashMap<>();
requestBody.put("ZID", 1000);
requestBody.put("Remark", "example");
byte[] updateZoneResult = request("POST", new HashMap<>(), new HashMap<>(), AK, SK, "UpdatePrivateZone", JSON.toJSONBytes(requestBody));
// 打印输出的结果
System.out.println("response body:");
if (updateZoneResult != null) {
System.out.println(new String(updateZoneResult, StandardCharsets.UTF_8));
} else {
System.out.println("null");
}
// (GET 请求)调用 ListPrivateZones API
HashMap<String, String> query = new HashMap<>();
query.put("ZoneName", "example.com");
byte[] checkZoneResult = request("GET", query, new HashMap<>(), AK, SK, "ListPrivateZones", new byte[]{});
// 打印输出的结果
System.out.println("response body:");
if (checkZoneResult != null) {
System.out.println(new String(checkZoneResult, StandardCharsets.UTF_8));
} else {
System.out.println("null");
}
}
}
下面的示例代码演示了如何基于 Golang 在调用 UpdatePrivateZone API 和 ListPrivateZones API 时对请求进行鉴权。
在运行示例代码之前,您需要 获取 Access Key ID 和 Secret Access Key。然后,您需要分别将 Access Key ID 和 Secret Access Key 的值传入示例代码中的 AccessKey 常量和 SecretAccessKey 常量。
package main
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
"time"
)
const Version = "2022-06-01"
const Service = "private_zone"
const Region = "cn-north-1"
const Host = "private-zone.volcengineapi.com"
// 第一步:准备辅助函数。
// sha256非对称加密
func hmacSHA256(key []byte, content string) []byte {
mac := hmac.New(sha256.New, key)
mac.Write([]byte(content))
return mac.Sum(nil)
}
// sha256 hash算法
func hashSHA256(content []byte) string {
h := sha256.New()
h.Write(content)
return hex.EncodeToString(h.Sum(nil))
}
// 第二步:准备需要用到的结构体定义。
// 签算请求结构体
type RequestParam struct {
Body []byte
Method string
Date time.Time
Path string
Host string
QueryList url.Values
}
// 身份证明结构体
type Credentials struct {
AccessKeyID string
SecretAccessKey string
Service string
Region string
}
// 签算结果结构体
type SignRequest struct {
XDate string
Host string
ContentType string
XContentSha256 string
Authorization string
}
// go http client
var httpClient = &http.Client{
Timeout: time.Second * 60,
Transport: &http.Transport{
MaxIdleConns: 100,
MaxConnsPerHost: 10,
IdleConnTimeout: time.Second * 15,
},
}
// 第三步:创建一个私网域名解析的 API 请求函数。签名计算的过程包含在该函数中。
func requestPrivateZone(method string, query map[string][]string, header map[string]string, ak string, sk string, action string, body []byte) ([]byte, error) {
// 第四步:在 requestPrivateZone 中,创建一个 HTTP 请求实例。
// 创建 HTTP 请求实例。该实例会在后续用到。
request, _ := http.NewRequest(method, "https://"+Host+"/", bytes.NewReader(body))
urlVales := url.Values{}
for k, v := range query {
urlVales[k] = v
}
urlVales["Action"] = []string{action}
urlVales["Version"] = []string{Version}
request.URL.RawQuery = urlVales.Encode()
for k, v := range header {
request.Header.Set(k, v)
}
// 第五步:创建身份证明。其中的 Service 和 Region 字段是固定的。ak 和 sk 分别代表 AccessKeyID 和 SecretAccessKey。同时需要初始化签名结构体。一些签名计算时需要的属性也在这里处理。
// 初始化身份证明
credential := Credentials{
AccessKeyID: ak,
SecretAccessKey: sk,
Service: Service,
Region: Region,
}
// 初始化签名结构体
requestParam := RequestParam{
Body: body,
Host: request.Host,
Path: "/",
Method: request.Method,
Date: time.Now().UTC(),
QueryList: request.URL.Query(),
}
// 第六步:接下来开始计算签名。在计算签名前,先准备好用于接收签算结果的 signResult 变量,并设置一些参数。
// 初始化签名结果的结构体
xDate := requestParam.Date.Format("20060102T150405Z")
shortXDate := xDate[:8]
XContentSha256 := hashSHA256(requestParam.Body)
contentType := "application/json"
signResult := SignRequest{
Host: requestParam.Host, // 设置Host
XContentSha256: XContentSha256, // 加密body
XDate: xDate, // 设置标准化时间
ContentType: contentType, // 设置Content-Type 为 application/json
}
// 第七步:计算 Signature 签名。
signedHeadersStr := strings.Join([]string{"content-type", "host", "x-content-sha256", "x-date"}, ";")
canonicalRequestStr := strings.Join([]string{
requestParam.Method,
requestParam.Path,
request.URL.RawQuery,
strings.Join([]string{"content-type:" + contentType, "host:" + requestParam.Host, "x-content-sha256:" + XContentSha256, "x-date:" + xDate}, "\n"),
"",
signedHeadersStr,
XContentSha256,
}, "\n")
hashedCanonicalRequest := hashSHA256([]byte(canonicalRequestStr))
credentialScope := strings.Join([]string{shortXDate, credential.Region, credential.Service, "request"}, "/")
stringToSign := strings.Join([]string{
"HMAC-SHA256",
xDate,
credentialScope,
hashedCanonicalRequest,
}, "\n")
kDate := hmacSHA256([]byte(credential.SecretAccessKey), shortXDate)
kRegion := hmacSHA256(kDate, credential.Region)
kService := hmacSHA256(kRegion, credential.Service)
kSigning := hmacSHA256(kService, "request")
signature := hex.EncodeToString(hmacSHA256(kSigning, stringToSign))
signResult.Authorization = fmt.Sprintf("HMAC-SHA256 Credential=%s, SignedHeaders=%s, Signature=%s", credential.AccessKeyID+"/"+credentialScope, signedHeadersStr, signature)
// 第八步:将 Signature 签名写入HTTP Header 中,并发送 HTTP 请求。
// 设置经过签名的5个HTTP Header
request.Header.Set("Host", signResult.Host)
request.Header.Set("Content-Type", signResult.ContentType)
request.Header.Set("X-Date", signResult.XDate)
request.Header.Set("X-Content-Sha256", signResult.XContentSha256)
request.Header.Set("Authorization", signResult.Authorization)
resp, err := httpClient.Do(request)
if err != nil {
return nil, err
}
body, err = ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return body, nil
}
/* main.go */
// 定义请求参数结构体
type UpdateZoneParam struct {
ZID uint64 `json:"ZID"`
Remark string `json:"Remark"`
}
func main() {
// (POST 请求)调用 UpdatePrivateZone API
bodyParam := UpdateZoneParam{
ZID: 100,
Remark: "example",
}
body, err := json.Marshal(&bodyParam)
if err != nil {
fmt.Printf("marshal failed: %v", err)
return
}
// 分别将 Access Key ID 和 Secret Access Key 的值传入 AK 常量和 SK 常量
AccessKey := "ak"
SecretAccessKey := "sk"
updatePrivateZoneResult, err := requestPrivateZone("POST", map[string][]string{}, map[string]string{}, AccessKey, SecretAccessKey, "UpdatePrivateZone", body)
if err != nil {
fmt.Printf("do request failed: %v", err)
return
}
// 打印输出的结果
fmt.Println(string(updatePrivateZoneResult))
// (GET 请求)调用 ListPrivateZones API
QueryParam := map[string][]string{"ZoneName": []string{"example.com"}}
ListPrivateZonesResult, err := requestPrivateZone("GET", QueryParam, map[string]string{}, AccessKey, SecretAccessKey,
"ListPrivateZones", []byte{})
if err != nil {
fmt.Printf("do request failed: %v", err)
return
}
// 打印输出的结果
fmt.Println(string(ListPrivateZonesResult))
}
下面的示例代码演示了如何基于 Python 3 在调用 UpdatePrivateZone API 和 ListPrivateZones API 时对请求进行鉴权。
在运行示例代码之前,您需要 获取 Access Key ID 和 Secret Access Key。然后,您需要分别将 Access Key ID 和 Secret Access Key 的值传入示例代码中的 AK 变量和 SK 变量。另外,示例代码使用了 requests 库,您可以通过 python3 -m pip install requests 命令安装 requests 库。
import datetime
import hashlib
import hmac
import json
from urllib.parse import quote
from collections import OrderedDict
import requests
Service = "private_zone"
Version = "2022-06-01"
Region = "cn-north-1"
Host = "private-zone.volcengineapi.com"
# 分别将 Access Key ID 和 Secret Access Key 的值传入 AK 变量和 SK 变量
AK = "ak"
SK = "sk"
def norm_query(params):
query = ""
for key in sorted(params.keys()):
if type(params[key]) == list:
for k in params[key]:
query = (
query + quote(key, safe="-_.~") + "=" + quote(k, safe="-_.~") + "&"
)
else:
query = (query + quote(key, safe="-_.~") + "=" + quote(params[key], safe="-_.~") + "&")
query = query[:-1]
return query.replace("+", "%20")
# 第一步:准备辅助函数。
# sha256 非对称加密
def hmac_sha256(key: bytes, content: str):
return hmac.new(key, content.encode("utf-8"), hashlib.sha256).digest()
# sha256 hash算法
def hash_sha256(content: str):
return hashlib.sha256(content.encode("utf-8")).hexdigest()
# 第二步:创建一个 API 请求函数。签名计算的过程包含在该函数中。
def request(method, query, header, ak, sk, action, body):
# 第三步:创建身份证明。其中的 Service 和 Region 字段是固定的。ak 和 sk 分别代表
# AccessKeyID 和 SecretAccessKey。同时需要初始化签名结构体。一些签名计算时需要的属性也在这里处理。
# 初始化身份证明结构体
credential = {
"access_key_id": ak,
"secret_access_key": sk,
"service": Service,
"region": Region,
}
# 初始化签名结构体
query = {"Action": action, "Version": Version, **query}
sorted_query = OrderedDict(sorted(query.items()))
request_param = {
"body":"",
"host": Host,
"path": "/",
"method": method,
"content_type": "application/json",
"date": datetime.datetime.utcnow(),
"query": sorted_query,
}
if method == "POST":
request_param["body"] = json.dumps(body)
# 第四步:接下来开始计算签名。在计算签名前,先准备好用于接收签算结果的 signResult 变量,并设置一些参数。
# 初始化签名结果的结构体
x_date = request_param["date"].strftime("%Y%m%dT%H%M%SZ")
short_x_date = x_date[:8]
x_content_sha256 = hash_sha256(request_param["body"])
sign_result = {
"Host": request_param["host"],
"X-Content-Sha256": x_content_sha256,
"X-Date": x_date,
"Content-Type": request_param["content_type"],
}
# 第五步:计算 Signature 签名。
signed_headers_str = ";".join(
["content-type", "host", "x-content-sha256", "x-date"]
)
canonical_request_str = "\n".join(
[request_param["method"],
request_param["path"],
norm_query(request_param["query"]),
"\n".join(
[
"content-type:" + request_param["content_type"],
"host:" + request_param["host"],
"x-content-sha256:" + x_content_sha256,
"x-date:" + x_date,
]
),
"",
signed_headers_str,
x_content_sha256,
]
)
hashed_canonical_request = hash_sha256(canonical_request_str)
credential_scope = "/".join([short_x_date, credential["region"], credential["service"], "request"])
string_to_sign = "\n".join(["HMAC-SHA256", x_date, credential_scope, hashed_canonical_request])
k_date = hmac_sha256(credential["secret_access_key"].encode("utf-8"), short_x_date)
k_region = hmac_sha256(k_date, credential["region"])
k_service = hmac_sha256(k_region, credential["service"])
k_signing = hmac_sha256(k_service, "request")
signature = hmac_sha256(k_signing, string_to_sign).hex()
sign_result["Authorization"] = "HMAC-SHA256 Credential={}, SignedHeaders={}, Signature={}".format(
credential["access_key_id"] + "/" + credential_scope,
signed_headers_str,
signature,
)
header = {**header, **sign_result}
# 第六步:将 Signature 签名写入 HTTP Header 中,并发送 HTTP 请求。
if method == "POST":
r = requests.post("https://{}{}".format(request_param["host"], request_param["path"]),
headers=header,
params=request_param["query"],
data=request_param["body"],
)
return r.json()
if method == "GET":
r = requests.get("https://{}{}".format(request_param["host"], request_param["path"]),
headers=header,
params=request_param["query"],
data=request_param["body"],
)
return r.json()
if __name__ == "__main__":
# (POST 请求)调用 UpdatePrivateZone API
request_body = {
"ZID": 100,
"Remark": "example",
}
update_private_zone_result = request("POST", {}, {}, AK, SK, "UpdatePrivateZone", request_body)
print(update_private_zone_result)
# (GET 请求)调用 ListPrivateZones API
request_query = {"ZoneName": "example.com"}
list_private_zones_result = request("GET", request_query, {}, AK, SK, "ListPrivateZones", {})
print(list_private_zones_result)
您可以使用以下任一方法提供鉴权信息。推荐您使用方法一。
您需要在请求头中包含以下参数:
| 参数名称 | 数据类型 | 是否必选 | 参数说明 | 示例 |
|---|---|---|---|---|
| X-Date | string | 是 | 表示签名计算的时间,以 UTC 表示。时间精度是秒。 |
20201103T104027Z |
| Authorization | string | 是 | 该参数表示鉴权字符串。Authorization 的伪代码结构如下: |
\ |
| ```plain | \ | |||
| HMAC-SHA256 Credential = {AccessKey}/{ShortDate}/{Region}/{Service}/{Request}, SignedHeaders={SignedHeaders}, Signature={Signature} | \ | |||
| ``` | \ | |||
Authorization 伪代码中的 Signature 参数表示签名。关于 Signature 参数的计算步骤,参见签名计算方式。关于 Authorization 伪代码中其他参数的说明,参见伪代码中参数的说明。 |
该参数表示一个结构体。结构体中包含了 Signature。 |
|||
| X-Security-Token | string | 否 | 如果您使用火山引擎账号的 Access Key ID 和 Secret Access Key 来计算 Authorization,则无需指定该参数。如果您使用的 Access Key ID 和 Secret Access Key 是安全令牌服务(STS)提供的,则需要指定该参数。该参数值就是 STS 颁发的临时安全凭证中的 SessionToken。参见 获取临时安全令牌。 | STSeyJBY2NvdW50SW |
请求示例
GET https://private-zone.volcengineapi.com/?Action=ListPrivateZones&Version=2022-06-01
X-Date: 20230116T073702Z
Authorization: HMAC-SHA256 Credential=AKLTMjYxYTZmYWU4ZWYzNGI2NDg8NTUxODE1ZGVhNmIxZmQ/20230116/cn-north-1/private_zone/request, SignedHeaders=x-content-sha256;x-date, Signature=5a394ce80456c7cdf989c28bd638807c8ead386eb15dd36e39952f405380aef2
ServiceName: private_zone
您需要在查询字符串中包含以下查询参数。
| 参数名称 | 数据类型 | 是否必选 | 参数说明 | 示例 |
|---|---|---|---|---|
| X-Date | string | 是 | 签名计算的时间,以 UTC 表示。时间精度是秒。 |
20201103T104027Z |
| X-Algorithm | string | 是 | 签名计算所使用的算法。该参数的值是 HMAC-SHA256。 |
HMAC-SHA256 |
| X-Credential | string | 是 | X-Credential 的伪代码结构如下: | \ |
| ```plain | \ | |||
| {AccessKey}/{ShortDate}/{Region}/{Service}/{Request} | \ | |||
| ``` | \ | |||
关于 X-Credential伪代码中参数的说明,参见伪代码中参数的说明。 |
AKLTMjI2ODVlYzI3ZGY1NGU4ZjhjYWRjMTlmNTM5OTZkYzE/20210913/cn-north-1/private_zone/request |
|||
| X-SignedHeaders | string | 是 | 参与签名计算的请求头参数。多个请求头参数使用分号(;)分隔。这些请求头参数是根据参数名称升序排序的。X-SignedHeaders 与 SignedHeaders 参数的定义是相同的。在您计算 CanonicalRequest 的参数值的时候需要使用 X-SignedHeaders。 |
host;x-content-sha256;x-date |
一般来说,X-SignedHeaders 的值是 host;x-content-sha256;x-date。您也可以指定任意请求头参数作为 X-SignedHeaders 的值。 |
||||
| X-Signature | string | 是 | 一个经过计算得到的签名。关于签名的计算步骤,参见签名计算方式。 |
本章节主要介绍签名是如何计算的。
HMAC 方法使用的是 HMAC-SHA256 算法。HexEncode 方法将字符串转换为十六进制编码格式的字符串。Signature 是基于 kSigning 和 StringToSign 参数计算而来的。Signature 的伪代码如下:
Signature = HexEncode(HMAC(kSigning, StringToSign))
kSigning 表示用来计算签名的密钥。要计算 kSigning,您必须先获取您账号的 Access Key Secret,然后使用以下伪代码生成 kSigning。
kSecret = <Your Access Key Secret>
kDate = HMAC(kSecret, ShortDate)
kRegion = HMAC(kDate, Region)
kService = HMAC(kRegion, Service)
kSigning = HMAC(kService, "request")
关于 kSigning 伪代码中参数的说明,参见伪代码中参数的说明。
StringToSign 表示用来计算签名的签名字符串。StringToSign 的伪代码如下:
// Hash 函数使用 SHA256 算法
StringToSign = Algorithm + '\n' + RequestDate + '\n' + CredentialScope + '\n' + HexEncode(Hash(CanonicalRequest))
关于 StringToSign 伪代码中 Algorithm 和 RequestDate 参数的说明,参见伪代码中参数的说明。StringToSign 伪代码中其他参数的说明如下。
CredentialScope
CredentialScope 表示凭证范围。CredentialScope 的伪代码如下:
{ShortDate}/{Region}/{Service}/{Request}
关于 CredentialScope 伪代码中参数的说明,参见伪代码中参数的说明。
CanonicalRequest
CanonicalRequest 表示规范的请求。CanonicalRequest 的伪代码如下:
HTTPRequestMethod + '\n' + CanonicalURI + '\n' + CanonicalQueryString + '\n' + CanonicalHeaders + '\n' + SignedHeaders + '\n' + HexEncode(Hash(RequestPayload))
CanonicalRequest 伪代码中参数的说明如下:
HTTPRequestMethod:请求方法。CanonicalURI:请求的 URI。CanonicalQueryString:规范的查询字符串。CanonicalQueryString 的值是通过以下规则生成的:
CanonicalHeaders:规范的请求头。CanonicalHeaders 是通过以下步骤生成的:
\n)。SignedHeaders:参见伪代码中参数的说明。HexEncode(Hash(RequestPayload)):一个计算值。该值是通过对请求正文中 payload 的值应用 SHA256 哈希算法计算得到的。以下表格包含了本文中多个伪代码中参数的说明。
| 参数名称 | 数据类型 | 参数说明 | 示例 |
|---|---|---|---|
| AccessKey | string | 您账号的 Access Key ID。参考获取 Access Key。 | AKLTMjI2ODVlYzI3ZGY1NGU4ZjhjYWRjMTlmNTM5OTZkYzE |
| RequestDate | string | 该参数与 X-Date 的定义相同。 |
20210913T081805Z |
| ShortDate | string | 该参数与 RequestDate 的定义相同,只不过时间精度是日。 |
20210913 |
| Region | string | 私网解析 PrivateZone 所在的地域。该参数的取值是 cn-north-1。 |
cn-north-1 |
| Service | string | 私网解析 PrivateZone 的服务名称。该参数的取值是 private_zone。 |
private_zone |
| SignedHeaders | string | 参与签名计算的请求头参数。多个请求头参数使用分号(;)分隔。这些请求头参数是根据参数名称升序排序的。 一般来说, SignedHeaders 的值是 host;x-content-sha256;x-date。您也可以指定任意请求头参数作为 SignedHeaders 的值。 |
host;x-content-sha256;x-date |
| Algorithm | string | 表示签名计算所使用的算法。该参数的取值为 HMAC-SHA256。 |
HMAC-SHA256 |
| Request | string | 该参数是一个常量,值是 request。 |
request |