全部产品
云市场

HTTP调用方式

更新时间:2019-03-07 16:43:18

概述

本文适用基于 API URL 发起 HTTP/HTTPS GET 请求的用户,如果您使用的是 SDK、阿里云 CLI 或者 API Explorer,可以跳过此环节。

发起 API 请求的 URL 由不同参数拼凑而成,有固定的 请求结构。URL 中包含 公共参数、您的 签名 和某个 API 的具体参数。每篇 API 文档均给出了 URL 请求示例供您参考,但是为了方便显示,我们并没有编码这些 URL 示例,您需要在发起请求前自行编码。我们根据您的签名验证了请求后,会 返回结果 给您。接口调用成功会显示返回参数,调用失败则显示相应报错,您可以根据公共错误码和具体 API 错误码分析排查。

请求结构

阿里云ENS API支持基于URL发起HTTP/HTTPS GET请求。请求参数需要包含在URL中。本文列举了GET请求中的结构解释,并提供了ENS的服务接入地址(Endpoint)。

结构示例

以下为StartInstance一条未编码的URL请求示例:

  1. https://ens.aliyuncs.com/?Action=StartInstance&InstanceId=i-instance1&<公共请求参数>

公共参数

以下公共请求参数适用于通过 URL 发送 GET 请求调用云服务器 ENS API。

名称 类型 是否必需 描述
Action String API 的名称。
AccessKeyId String 访问密钥 ID。AccessKey 用于调用 API。
Signature String 您的签名。
SignatureMethod String 签名方式。取值范围:HMAC-SHA1。
SignatureVersion String 签名算法版本。取值范围:1.0。
SignatureNonce String 签名唯一随机数。用于防止网络重放攻击,建议您每一次请求都使用不同的随机数。
Timestamp String 请求的时间戳。按照ISO8601标准表示,并需要使用UTC时间,格式为yyyy-MM-ddTHH:mm:ssZ。示例:2018-01-01T12:00:00Z 表示北京时间 2018 年 01 月 01 日 20 点 00 分 00 秒。
Version String API 的版本号,格式为 YYYY-MM-DD。取值范围:2017-11-10。
Format String 返回参数的语言类型。取值范围:json xml。默认值:xml。

请求示例

http请求串

  1. https://ens.aliyuncs.com/?Action=XXXXXX
  2. &Format=xml
  3. &Version=2017-11-10
  4. &Signature=Pc5WB8gokVn0xfeu%2FZV%2BiNM1dgI%3D
  5. &SignatureMethod=HMAC-SHA1
  6. &SignatureNonce=15215528852396
  7. &SignatureVersion=1.0
  8. &AccessKeyId=key-test
  9. &Timestamp=2018-01-01T12:00:00Z

签名机制

对于每一次HTTP或者HTTPS协议请求,我们会根据访问中的签名信息验证访问请求者身份。具体由使用AccessKeyID和AccessKeySecret对称加密验证实现。

AccessKey相当于用户密码,AccessKey用于调用API,而用户密码用于登录ENS控制台 。其中AccessKeyID是访问者身份,AccessKeySecret是加密签名字符串和服务器端验证签名字符串的密钥,必须严格保密谨防泄露。

步骤 1. 构造规范化请求字符串

  1. 排序参数。排序规则以首字母顺序排序,排序参数包括 公共请求参数 和接口自定义参数,不包括公共请求参数中的 Signature 参数。
  2. 编码参数。使用UTF-8字符集按照 RFC3986 规则编码请求参数和参数取值,编码规则如下:

    • 字符A~Z、a~z、0~9以及字符 -、_、.、~ 不编码。

    • 其它字符编码成 %XY 的格式,其中 XY 是字符对应ASCII码的16进制。示例:半角双引号(”)对应 %22。

    • 扩展的UTF-8字符,编码成 %XY%ZA… 的格式。

    • 空格( )编码成 %20,而不是加号(+)。

    • 该编码方式与 application/x-www-form-urlencoded MIME格式编码算法相似,但又有所不同。

    • 如果您使用的是Java标准库中的 java.net.URLEncoder,可以先用标准库中 percentEncode 编码,随后将编码后的字符中加号(+)替换为 %20、星号(*)替换为 %2A、%7E 替换为波浪号(~),即可得到上述规则描述的编码字符串。

  1. private static final String ENCODING = "UTF-8";
  2. private static String percentEncode(String value) throws UnsupportedEncodingException {
  3. return value != null ? URLEncoder.encode(value, ENCODING).replace("+", "%20").replace("*", "%2A").replace("%7E", "~") : null;
  4. }

3.使用等号(=)连接编码后的请求参数和参数取值。4.使用与号(&)连接编码后的请求参数,注意参数排序与 步骤1 一致。

步骤 2. 构造签名字符串

1.构造待签名字符串 StringToSign。您可以同样使用 percentEncode 处理上一步构造的规范化请求字符串,规则如下:

  1. StringToSign=
  2. HTTPMethod + "&" + //HTTPMethod:发送请求的 HTTP 方法,例如 GET。
  3. percentEncode("/") + "&" + //percentEncode("/"):字符(/)UTF-8 编码得到的值,即 %2F。
  4. percentEncode(CanonicalizedQueryString) //您的规范化请求字符串。

2.按照 RFC2104 的定义,计算待签名字符串 StringToSign 的HMAC-SHA1值。示例使用的是Java Base64编码方法。

  1. Signature = Base64( HMAC-SHA1( AccessSecret, UTF-8-Encoding-Of(StringToSign) ) )

调用示例

普通https调用

  1. import java.io.UnsupportedEncodingException;
  2. import java.net.URLEncoder;
  3. import java.security.InvalidKeyException;
  4. import java.security.NoSuchAlgorithmException;
  5. import java.text.SimpleDateFormat;
  6. import java.util.ArrayList;
  7. import java.util.Arrays;
  8. import java.util.Date;
  9. import java.util.HashMap;
  10. import java.util.List;
  11. import java.util.Map;
  12. import java.util.SimpleTimeZone;
  13. import java.util.UUID;
  14. import javax.crypto.Mac;
  15. import javax.crypto.spec.SecretKeySpec;
  16. import org.apache.commons.codec.binary.Base64;
  17. import org.apache.http.NameValuePair;
  18. import org.apache.http.message.BasicNameValuePair;
  19. public class HttpUtilEnsTest {
  20. private static final String ISO8601_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
  21. public static void main(String[] args) throws Exception {
  22. testEnsApi();
  23. }
  24. public static void testEnsApi() throws Exception {
  25. final String HTTP_METHOD = "GET";
  26. Map<String, String> parameters = new HashMap<String, String>();
  27. String utc = formatIso8601Date(new Date());
  28. String uuid = UUID.randomUUID().toString();
  29. // 加入请求参数
  30. parameters.put("Action", "DescribeInstances");
  31. parameters.put("Version", "2017-11-10");
  32. parameters.put("AccessKeyId", "xxxx");
  33. parameters.put("Timestamp", utc);
  34. parameters.put("SignatureMethod", "HMAC-SHA1");
  35. parameters.put("SignatureVersion", "1.0");
  36. parameters.put("SignatureNonce", uuid);
  37. parameters.put("Format", "JSON");
  38. parameters.put("InstanceId", "i-5gik8tsve39wz4aej3uy1nxk3");
  39. List<NameValuePair> nvps = new ArrayList<NameValuePair>();
  40. nvps.add(new BasicNameValuePair("Action", "DescribeInstances"));
  41. nvps.add(new BasicNameValuePair("Version", "2017-11-10"));
  42. nvps.add(new BasicNameValuePair("AccessKeyId", "xxxx"));
  43. nvps.add(new BasicNameValuePair("Timestamp", utc));
  44. nvps.add(new BasicNameValuePair("SignatureMethod", "HMAC-SHA1"));
  45. nvps.add(new BasicNameValuePair("SignatureVersion", "1.0"));
  46. nvps.add(new BasicNameValuePair("SignatureNonce", uuid));
  47. nvps.add(new BasicNameValuePair("Format", "JSON"));
  48. nvps.add(new BasicNameValuePair("InstanceId", "i-5gik8tsve39wz4aej3uy1nxk3"));
  49. // 对参数进行排序
  50. String[] sortedKeys = parameters.keySet().toArray(new String[]{});
  51. Arrays.sort(sortedKeys);
  52. final String SEPARATOR = "&";
  53. // 生成stringToSign字符串
  54. StringBuilder stringToSign = new StringBuilder();
  55. stringToSign.append(HTTP_METHOD).append(SEPARATOR);
  56. stringToSign.append(percentEncode("/")).append(SEPARATOR);
  57. StringBuilder canonicalizedQueryString = new StringBuilder();
  58. for(String key : sortedKeys) {
  59. // 这里注意对key和value进行编码
  60. canonicalizedQueryString.append("&")
  61. .append(percentEncode(key)).append("=")
  62. .append(percentEncode(parameters.get(key)));
  63. }
  64. // 这里注意对canonicalizedQueryString进行编码
  65. stringToSign.append(percentEncode(
  66. canonicalizedQueryString.toString().substring(1)));
  67. String sign = createSign(stringToSign.toString());
  68. nvps.add(new BasicNameValuePair("Signature", sign));
  69. String rtnDescribeImagesJson = HttpUtils.get("http://ens.aliyuncs.com", null, nvps, 6000);
  70. System.out.println("---rtn----"+rtnDescribeImagesJson);
  71. }
  72. private static String formatIso8601Date(Date date) {
  73. SimpleDateFormat df = new SimpleDateFormat(ISO8601_DATE_FORMAT);
  74. df.setTimeZone(new SimpleTimeZone(0, "GMT"));
  75. return df.format(date);
  76. }
  77. private static final String ENCODING = "UTF-8";
  78. private static String percentEncode(String value) throws UnsupportedEncodingException {
  79. return value != null ? URLEncoder.encode(value, ENCODING).replace("+", "%20").replace("*", "%2A").replace("%7E", "~") : null;
  80. }
  81. private static String createSign(String stringToSign) throws InvalidKeyException, UnsupportedEncodingException, NoSuchAlgorithmException{
  82. final String ALGORITHM = "HmacSHA1";
  83. final String ENCODING = "UTF-8";
  84. String key = "xxxxxxxx&";//密钥后加&符
  85. Mac mac = Mac.getInstance(ALGORITHM);
  86. mac.init(new SecretKeySpec(key.getBytes(ENCODING), ALGORITHM));
  87. byte[] signData = mac.doFinal(stringToSign.getBytes(ENCODING));
  88. String signature = new String(Base64.encodeBase64(signData));
  89. return signature;
  90. }
  91. }

通用sdk调用

安装阿里云SDK,如果您使用Maven管理Java项目,可以通过在pom.xml文件中添加Maven依赖安装阿里云SDK。您可以在Maven库中查找各云产品的Maven依赖信息。

  1. <dependency>
  2. <groupId>com.aliyun</groupId>
  3. <artifactId>aliyun-java-sdk-core</artifactId>
  4. <version>3.7.1</version>
  5. </dependency>

代码调用如下

  1. public static void main(String[] args) throws ServerException, ClientException {
  2. // region,ak,secret
  3. // 创建DefaultAcsClient实例并初始化
  4. DefaultProfile profile = DefaultProfile.getProfile(
  5. "<your-region-id>", // 您的地域ID
  6. "<your-access-key-id>", // 您的AccessKey ID
  7. "<your-access-key-secret>"); // 您的AccessKey Secret
  8. IAcsClient client = new DefaultAcsClient(profile);
  9. CommonRequest request = new CommonRequest();
  10. request.setDomain("ens.aliyuncs.com");
  11. request.setVersion("2017-11-10");
  12. request.setAction("DescribeInstances");
  13. request.putQueryParameter("PageNumber", "1");
  14. request.putQueryParameter("InstanceId", "i-5fdtkui1nk8o1dkt55o8lthgj");
  15. request.putQueryParameter("PageSize", "1");
  16. CommonResponse response = client.getCommonResponse(request);
  17. System.out.println(response.getData());
  18. }