本文档涉及的一些常用术语如下:
术语 | 全称 | 中文 | 说明 |
---|---|---|---|
Instance | Instance | 实例 | 指代一台云服务器。 |
Region | Region | 地域 | 表示资源所在的地域,每个地域包含一个或多个可用区。 |
Zone | Zone | 可用区 | 指腾讯云在同一 地域 内电力和网络互相独立的物理数据中心。目标是能够保证可用区之间故障相互隔离,不出现故障扩散,使得用户的业务持续在线服务。 |
Image | Image | 镜像 | CVM实例上软件环境的拷贝,一般包括操作系统和已安装的软件;我们使用镜像来创建实例。 |
SecurityGroup | Security Group | 安全组 | 一种有状态的包过滤功能的虚拟防火墙,用于控制CVM实例的网络访问, 是一种重要的网络安全隔离手段。 |
EIP | Elastic IP | 弹性IP | 弹性IP是公网IP的一种。与普通公网IP不同的是,弹性IP归属于用户账户而不是实例;实例与公网IP的映射关系随时可以更改。 |
无 | 无 | 包年包月 | 一种计费模式,参看 计费模式说明。 |
无 | 无 | 按量计费 | 一种计费模式,参看 计费模式说明。 |
输入参数与返回参数释义
Limit 和 Offset
用来控制分页的参数;Limit 为单次返回的最多条目数量,Offset 为偏移量。当相应结果是列表形式时,如果数量超过了 Limit 所限定的值,那么只返回 Limit 个值。
举例来说,参数 Offset=0&Limit=20 返回第 0 到 20 项,Offset=20&Limit=20 返回第 20 到 40 项,Offset=40&Limit=20 返回第 40 到 60 项;以此类推。
同时输入多个参数的格式。当遇到形如这样的格式时,那么该输入参数可以同时传多个。例如:
GET 请求或者 POST x-www-form-urlencoded 请求:Ids.0=ins-r8hr2upy&Ids.1=ins-5d8a23rs&Ids.2=ins--dcs9x3gz
以此类推(以下标 0 开始)。
POST json 请求:{"Ids": ["ins-r8hr2upy", "ins-5d8a23rs", "ins--dcs9x3gz"]}
1. 申请安全凭证
在第一次使用云API之前,请前往云API密钥页面申请安全凭证。 安全凭证包括 SecretId 和 SecretKey:
申请安全凭证的具体步骤如下:
注意:开发商帐号最多可以拥有两对 SecretId / SecretKey。
2. 生成签名串
有了安全凭证SecretId 和 SecretKey后,就可以生成签名串了。以下是生成签名串的详细过程:
假设用户的 SecretId 和 SecretKey 分别是:
注意:这里只是示例,请根据用户实际申请的 SecretId 和 SecretKey 进行后续操作!
以云服务器查看实例列表(DescribeInstances)请求为例,当用户调用这一接口时,其请求参数可能如下:
参数名称 | 中文 | 参数值 |
---|---|---|
Action | 方法名 | DescribeInstances |
SecretId | 密钥Id | AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE |
Timestamp | 当前时间戳 | 1465185768 |
Nonce | 随机正整数 | 11886 |
Region | 实例所在区域 | ap-guangzhou |
InstanceIds.0 | 待查询的实例ID | ins-09dx96dg |
Offset | 偏移量 | 0 |
Limit | 最大允许输出 | 20 |
Version | 接口版本号 | 2017-03-12 |
2.1. 对参数排序
首先对所有请求参数按参数名的字典序( ASCII 码)升序排序。注意:1)只按参数名进行排序,参数值保持对应即可,不参与比大小;2)按 ASCII 码比大小,如 InstanceIds.2 要排在 InstanceIds.12 后面,不是按字母表,也不是按数值。用户可以借助编程语言中的相关排序函数来实现这一功能,如 php 中的 ksort 函数。上述示例参数的排序结果如下:
{
'Action' : 'DescribeInstances',
'InstanceIds.0' : 'ins-09dx96dg',
'Limit' : 20,
'Nonce' : 11886,
'Offset' : 0,
'Region' : 'ap-guangzhou',
'SecretId' : 'AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE',
'Timestamp' : 1465185768,
'Version': '2017-03-12',
}
使用其它程序设计语言开发时,可对上面示例中的参数进行排序,得到的结果一致即可。
2.2. 拼接请求字符串
此步骤生成请求字符串。 将把上一步排序好的请求参数格式化成“参数名称”=“参数值”的形式,如对 Action 参数,其参数名称为 "Action" ,参数值为 "DescribeInstances" ,因此格式化后就为 Action=DescribeInstances 。 注意:“参数值”为原始值而非url编码后的值。
然后将格式化后的各个参数用"&"拼接在一起,最终生成的请求字符串为:
Action=DescribeInstances&InstanceIds.0=ins-09dx96dg&Limit=20&Nonce=11886&Offset=0&Region=ap-guangzhou&SecretId=AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE&Timestamp=1465185768&Version=2017-03-12
2.3. 拼接签名原文字符串
此步骤生成签名原文字符串。 签名原文字符串由以下几个参数构成:
签名原文串的拼接规则为: 请求方法 + 请求主机 +请求路径 + ? + 请求字符串
示例的拼接结果为:
GETcvm.tencentcloudapi.com/?Action=DescribeInstances&InstanceIds.0=ins-09dx96dg&Limit=20&Nonce=11886&Offset=0&Region=ap-guangzhou&SecretId=AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE&Timestamp=1465185768&Version=2017-03-12
2.4. 生成签名串
此步骤生成签名串。 首先使用 HMAC-SHA1 算法对上一步中获得的签名原文字符串进行签名,然后将生成的签名串使用 Base64 进行编码,即可获得最终的签名串。
具体代码如下,以 PHP 语言为例:
$secretKey = 'Gu5t9xGARNpq86cd98joQYCN3EXAMPLE';
$srcStr = 'GETcvm.tencentcloudapi.com/?Action=DescribeInstances&InstanceIds.0=ins-09dx96dg&Limit=20&Nonce=11886&Offset=0&Region=ap-guangzhou&SecretId=AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE&Timestamp=1465185768&Version=2017-03-12';
$signStr = base64_encode(hash_hmac('sha1', $srcStr, $secretKey, true));
echo $signStr;
最终得到的签名串为:
EliP9YW3pW28FpsEdkXt/+WcGeI=
使用其它程序设计语言开发时,可用上面示例中的原文进行签名验证,得到的签名串与例子中的一致即可。
3. 签名串编码
生成的签名串并不能直接作为请求参数,需要对其进行 URL 编码。
如上一步生成的签名串为 EliP9YW3pW28FpsEdkXt/+WcGeI= ,最终得到的签名串请求参数(Signature)为:EliP9YW3pW28FpsEdkXt%2f%2bWcGeI%3d,它将用于生成最终的请求 URL。
注意:如果用户的请求方法是 GET,或者请求方法为 POST 同时 Content-Type 为 application/x-www-form-urlencoded,则发送请求时所有请求参数的值均需要做 URL 编码,参数键和=符号不需要编码。非 ASCII 字符在 URL 编码前需要先以 UTF-8 进行编码。
注意:有些编程语言的 http 库会自动为所有参数进行 urlencode,在这种情况下,就不需要对签名串进行 URL 编码了,否则两次 URL 编码会导致签名失败。
注意:其他参数值也需要进行编码,编码采用 RFC 3986。使用 %XY 对特殊字符例如汉字进行百分比编码,其中“X”和“Y”为十六进制字符(0-9 和大写字母 A-F),使用小写将引发错误。
4. 签名失败
根据实际情况,存在以下签名失败的错误码,请根据实际情况处理
错误代码 | 错误描述 |
---|---|
AuthFailure.SignatureExpire | 签名过期 |
AuthFailure.SecretIdNotFound | 密钥不存在 |
AuthFailure.SignatureFailure | 签名错误 |
AuthFailure.TokenFailure | token 错误 |
AuthFailure.InvalidSecretId | 密钥非法(不是云 API 密钥类型) |
5. 签名演示
在实际调用 API 3.0 时,推荐使用配套的腾讯云 SDK 3.0 ,SDK 封装了签名的过程,开发时只关注产品提供的具体接口即可。
为了更清楚的解释签名过程,下面以实际编程语言为例,将上述的签名过程具体实现。请求的域名、调用的接口和参数的取值都以上述签名过程为准,代码只为解释签名过程,并不具备通用性,实际开发请尽量使用 SDK 。
最终输出的 url 可能为:https://cvm.tencentcloudapi.com/?Action=DescribeInstances&InstanceIds.0=ins-09dx96dg&Limit=20&Nonce=11886&Offset=0&Region=ap-guangzhou&SecretId=AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE&Signature=EliP9YW3pW28FpsEdkXt%2F%2BWcGeI%3D&Timestamp=1465185768&Version=2017-03-12
注意:由于示例中的密钥是虚构的,时间戳也不是系统当前时间,因此如果将此 url 在浏览器中打开或者用 curl 等命令调用时会返回鉴权错误:签名过期。为了得到一个可以正常返回的 url ,需要修改示例中的 SecretId 和 SecretKey 为真实的密钥,并使用系统当前时间戳作为 Timestamp 。
注意:在下面的示例中,不同编程语言,甚至同一语言每次执行得到的 url 可能都有所不同,表现为参数的顺序不同,但这并不影响正确性。只要所有参数都在,且签名计算正确即可。
注意:以下代码仅适用于 API 3.0,不能直接用于其他的签名流程,即使是旧版的 API ,由于存在细节差异也会导致签名计算错误,请以对应的实际文档为准。
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 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 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 params = new TreeMap(); // 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", "AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE"); // 公共参数
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), "Gu5t9xGARNpq86cd98joQYCN3EXAMPLE", "HmacSHA1")); // 公共参数
System.out.println(getUrl(params));
}
}
GITHUT地址
package com.tencentcloudapi.es.v20180416;
import java.lang.reflect.Type;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.AbstractClient;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.JsonResponseModel;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.es.v20180416.models.*;
public class EsClient extends AbstractClient{
private static String endpoint = "es.tencentcloudapi.com";
private static String version = "2018-04-16";
/**
* 构造client
* @param credential 认证信息实例
* @param region 产品地域
*/
public EsClient(Credential credential, String region) {
this(credential, region, new ClientProfile());
}
/**
* 构造client
* @param credential 认证信息实例
* @param region 产品地域
* @param profile 配置实例
*/
public EsClient(Credential credential, String region, ClientProfile profile) {
super(EsClient.endpoint, EsClient.version, credential, region, profile);
}
/**
*创建指定规格的ES集群实例
* @param req CreateInstanceRequest
* @return CreateInstanceResponse
* @throws TencentCloudSDKException
*/
public CreateInstanceResponse CreateInstance(CreateInstanceRequest req) throws TencentCloudSDKException{
JsonResponseModel rsp = null;
try {
Type type = new TypeToken>() {
}.getType();
rsp = gson.fromJson(this.internalRequest(req, "CreateInstance"), type);
} catch (JsonSyntaxException e) {
throw new TencentCloudSDKException(e.getMessage());
}
return rsp.response;
}
/**
*销毁集群实例
* @param req DeleteInstanceRequest
* @return DeleteInstanceResponse
* @throws TencentCloudSDKException
*/
public DeleteInstanceResponse DeleteInstance(DeleteInstanceRequest req) throws TencentCloudSDKException{
JsonResponseModel rsp = null;
try {
Type type = new TypeToken>() {
}.getType();
rsp = gson.fromJson(this.internalRequest(req, "DeleteInstance"), type);
} catch (JsonSyntaxException e) {
throw new TencentCloudSDKException(e.getMessage());
}
return rsp.response;
}
/**
*查询用户该地域下符合条件的ES集群的日志
* @param req DescribeInstanceLogsRequest
* @return DescribeInstanceLogsResponse
* @throws TencentCloudSDKException
*/
public DescribeInstanceLogsResponse DescribeInstanceLogs(DescribeInstanceLogsRequest req) throws TencentCloudSDKException{
JsonResponseModel rsp = null;
try {
Type type = new TypeToken>() {
}.getType();
rsp = gson.fromJson(this.internalRequest(req, "DescribeInstanceLogs"), type);
} catch (JsonSyntaxException e) {
throw new TencentCloudSDKException(e.getMessage());
}
return rsp.response;
}
/**
*查询实例指定条件下的操作记录
* @param req DescribeInstanceOperationsRequest
* @return DescribeInstanceOperationsResponse
* @throws TencentCloudSDKException
*/
public DescribeInstanceOperationsResponse DescribeInstanceOperations(DescribeInstanceOperationsRequest req) throws TencentCloudSDKException{
JsonResponseModel rsp = null;
try {
Type type = new TypeToken>() {
}.getType();
rsp = gson.fromJson(this.internalRequest(req, "DescribeInstanceOperations"), type);
} catch (JsonSyntaxException e) {
throw new TencentCloudSDKException(e.getMessage());
}
return rsp.response;
}
/**
*查询用户该地域下符合条件的所有实例
* @param req DescribeInstancesRequest
* @return DescribeInstancesResponse
* @throws TencentCloudSDKException
*/
public DescribeInstancesResponse DescribeInstances(DescribeInstancesRequest req) throws TencentCloudSDKException{
JsonResponseModel rsp = null;
try {
Type type = new TypeToken>() {
}.getType();
rsp = gson.fromJson(this.internalRequest(req, "DescribeInstances"), type);
} catch (JsonSyntaxException e) {
throw new TencentCloudSDKException(e.getMessage());
}
return rsp.response;
}
/**
*重启ES集群实例(用于系统版本更新等操作)
* @param req RestartInstanceRequest
* @return RestartInstanceResponse
* @throws TencentCloudSDKException
*/
public RestartInstanceResponse RestartInstance(RestartInstanceRequest req) throws TencentCloudSDKException{
JsonResponseModel rsp = null;
try {
Type type = new TypeToken>() {
}.getType();
rsp = gson.fromJson(this.internalRequest(req, "RestartInstance"), type);
} catch (JsonSyntaxException e) {
throw new TencentCloudSDKException(e.getMessage());
}
return rsp.response;
}
/**
*对集群进行扩缩容,修改实例名称,修改配置,重置密码, 添加Kibana黑白名单等操作。参数中InstanceId为必传参数,ForceRestart为选填参数,剩余参数传递组合及含义如下:
InstanceName:修改实例名称(仅用于标识实例)
NodeNum:集群数据节点横向扩缩容
NodeType, DiskSize:集群数据节点纵向扩缩容
MasterNodeNum: 集群专用主节点横向扩缩容
MasterNodeType, MasterNodeDiskSize: 集群专用主节点纵向扩缩容
EsConfig:修改集群配置
Password:修改集群密码
EsAcl:修改Kibana密码
CosBackUp: 设置集群COS自动备份信息
以上参数组合只能传递一种,多传或少传均会导致请求失败
* @param req UpdateInstanceRequest
* @return UpdateInstanceResponse
* @throws TencentCloudSDKException
*/
public UpdateInstanceResponse UpdateInstance(UpdateInstanceRequest req) throws TencentCloudSDKException{
JsonResponseModel rsp = null;
try {
Type type = new TypeToken>() {
}.getType();
rsp = gson.fromJson(this.internalRequest(req, "UpdateInstance"), type);
} catch (JsonSyntaxException e) {
throw new TencentCloudSDKException(e.getMessage());
}
return rsp.response;
}
}
API 概览
调用方式
实例相关接口