V2版本RPC风格请求体&签名机制
本文介绍了阿里云 OpenAPI 的 RPC 风格接口,涵盖请求的组成部分、如何构造 OpenAPI 请求、获取返回结果的方法以及签名机制等。阿里云 RPC OpenAPI 向开发者提供 HTTP 接口,方便自研阿里云 RPC 调用风格的 OpenAPI SDK。
不再推荐使用该访问方式,请移步参考V3版本请求体&签名机制。
RPC 风格简介
RPC(Remote Procedure Call)是一种允许客户端以类似本地函数调用方式远程调用服务端方法的协议。阿里云的 RPC 接口主要支持以下两种 HTTP 方法:
GET:用于从服务器获取资源。
POST:用于向服务器提交数据或请求操作。
HTTP 请求结构
一个完整的阿里云 RPC 请求由以下部分组成:
名称 | 是否必选 | 描述 | 示例值 |
协议 | 是 | 支持通过 | https:// |
服务地址 | 是 | 即 Endpoint。您可以查阅不同云产品的服务接入地址文档,在OpenAPI中的服务区域可查找。 | ecs.aliyuncs.com |
公共请求参数 | 是 | 阿里云 OpenAPI 的公共请求参数,更多信息,请参见下文公共请求参数。 | Action |
接口自定义请求参数 | 否 | 每个 OpenAPI 自定义的请求参数,建议您在阿里云 OpenAPI 开发者门户进行试用。 | RegionId |
HTTPMethod | 是 | RPC 请求 Method 支持 POST 或者 GET。 | GET |
公共请求参数
每个 RPC 请求都需包含以下关键参数:
名称 | 类型 | 是否必选 | 描述 | 示例值 |
Action | String | 是 | API 的名称。您可以访问阿里云 OpenAPI 开发者门户,搜索您想调用的 OpenAPI 。 | CreateInstance |
Version | String | 是 | API 版本。您可以访问阿里云 OpenAPI 开发者门户,查看您调用 OpenAPI 对应的 API 版本。例如短信服务产品,您可以通过查看云产品主页中看到API 版本为 2017-05-25。 | 2014-05-26 |
Format | String | 否 | 指定返回数据格式,可选 JSON 或 XML,默认为 XML。 | JSON |
AccessKeyId | String | 是 | 阿里云访问密钥 ID。您可以在RAM 控制台查看您的 AccessKeyId。如需创建 AccessKey,请参见创建AccessKey。 | yourAccessKeyId |
SignatureNonce | String | 是 | 签名唯一随机数。用于防止网络重放攻击,建议您每一次请求都使用不同的随机数,随机数位数无限制。 | 15215528852396 |
Timestamp | String | 是 | 当前时间戳,有效期为31分钟,即生成时间戳后需要在31分钟内发起请求。按照时间格式标准表示,并需要使用 UTC时间,格式为 示例: | 2018-01-01T12:00:00Z |
SignatureMethod | String | 是 | 签名方式。目前为固定值 | HMAC-SHA1 |
SignatureVersion | String | 是 | 签名算法版本。目前为固定值 | 1.0 |
Signature | String | 是 | 请求签名,用户请求的身份验证。更多信息,请参见后文签名机制。 | Pc5WB8gokVn0xfeu%2FZV%2BiNM1dgI%3D |
接口请求构造
步骤一:构造接口 URL
接口 URL 由以下部分组成:
[协议][服务地址]?[公共参数][业务请求参数]
。POST 方法应将业务参数放于请求体中,GET 方法的参数则在 URL 查询字符串中。
对请求参数进行规范化编码。例如: Timestamp 的参数值为 2016-02-23T12:46:24Z ,编码后为 2016-02-23T12%3A46%3A24Z 。编码方式请参见参数编码方式。
接口 URL 示例:
http://ecs.aliyuncs.com/?SignatureVersion=1.0&Action=DescribeDedicatedHosts&Format=XML&SignatureNonce=3ee8c1b8-xxxx-xxxx-xxxx-xxxxxxxxx&Version=2014-05-26&AccessKeyId=testid&Signature=OLeaidS1JvxuMvnyHOwuJ%2BuX5qY%3D&SignatureMethod=HMAC-SHA1&Timestamp=2016-02-23T12%3A46%3A24Z&RegionId=cn-hangzhou&Status=Available
步骤二:发起接口调用
GET 方法可使用浏览器、curl 或者 wget 等工具发起请求。
POST方法需在请求体中传入业务请求参数,并设置请求头的
Content-Type
为application/x-www-form-urlencoded
。
接口返回结果
返回结果主要有 XML 和 JSON 两种格式,默认为 XML ,可通过公共请求参数Format
指定返回结果的格式。
为了便于您查看,API 文档返回示例均进行了换行和缩进等处理,实际返回结果无换行和缩进处理。
当接口调用成功时,将返回请求 ID,HTTP 状态码为 2xx(不显示在响应正文中)。成功响应示例如下:
XML :
<?xml version="1.0" encoding="UTF-8"?> <!--结果的根结点-->
<ActionResponse> <!--返回请求标签-->
<RequestId>4C467B38-3910-447D-87BC-AC049166F216</RequestId> <!--返回结果数据-->
</ActionResponse>
JSON :
{
"RequestId": "4C467B38-3910-447D-87BC-AC049166F216" /* 返回结果数据 */
}
接口调用出错时,返回请求 ID、服务节点、错误码和错误信息,HTTP 状态码为 4xx 或 5xx。错误响应示例如下:
XML :
<?xml version="1.0" encoding="UTF-8"?><!--结果的根结点-->
<Error>
<RequestId>540CFF28-407A-40B5-B6A5-74Bxxxxxxxxx</RequestId> <!--请求 ID-->
<HostId>ecs.aliyuncs.com</HostId> <!--服务节点-->
<Code>MissingParameter.CommandId</Code> <!--错误码-->
<Message>The input parameter “CommandId” that is mandatory for processing this request is not supplied.</Message> <!--错误信息-->
</Error>
JSON :
{
"RequestId": "540CFF28-407A-40B5-B6A5-74Bxxxxxxxxx", /* 请求 ID */
"HostId": "ecs.aliyuncs.com", /* 服务节点 */
"Code": "MissingParameter.CommandId", /* 错误码 */
"Message": "The input parameter “CommandId” that is mandatory for processing this request is not supplied." /* 错误信息 */
}
接口调用出错后,您可以根据返回的 RequestId,在阿里云OpenAPI开发者门户-诊断中排查。此外,您还可以查阅公共错误码以及API 错误中心。当您无法排查错误时,可以提交工单,并在工单中注明服务节点 HostId 和 RequestId。
签名机制
为了确保 API 的安全性,每个请求都需通过签名(Signature)进行身份验证。以下是签名计算的步骤:
步骤一:构造规范化请求字符串
1、参数排序:按照参数首字母的字典顺序对参数排序,排序参数包括公共请求参数和接口自定义参数(即 OpenAPI 文档中的请求参数),不包括公共请求参数中的Signature
参数。 公共请求参数详情,请参见上文公共请求参数。伪代码如下:
// 例:参数名集合 {b, a, C} 排序后为 {C, a, b}
sortParams = sorted(params.keys())
2、编码参数:使用 UTF-8 字符集按照RFC3986规则编码请求参数和参数取值,编码具体规则请参看参数编码方式。为方便表述,我们将此步骤的编码方法,命名为 encodeURIComponent
。伪代码如下:
// 例:请求参数为测试,参数取值为中文 编码后分别是%E6%B5%8B%E8%AF%95和%E4%B8%AD%E6%96%87
encodeURIComponent(sortParams.keys, sortParams.values)
3、连接参数:使用等号(=)连接第二步得到的编码后请求参数和参数值。然后用&
连接所有参数。注意参数排序与第1步一致。伪代码如下:
// 例:编码后请求参数为test,参数取值为testvalue,则拼接为test=testvalue
encodeURIComponentParam.key=encodeURIComponentParam.value
得到了规范化请求字符串CanonicalizedQueryString
。
步骤二:构造签名字符串
1、构造待签名字符串 stringToSign
。该字符串构造规则的伪代码如下:
String stringToSign =
HTTPMethod + "&" + // HTTPMethod:发送请求的 HTTP 方法,例如 GET。
encodeURIComponent("/") + "&" + // encodeURIComponent 为步骤一第2步的编码方法
encodeURIComponent(CanonicalizedQueryString) // CanonicalizedQueryString 为步骤一获取的规范化请求字符串。
2、计算签名。按照RFC2104的定义,通过您传入的 AccessKeyId 对应的密钥 AccessSecret,使用 HMAC-SHA1
的签名算法,计算待签名字符串StringToSign
的签名。其中 Base64() 为编码计算函数,HMAC_SHA1() 为 HMAC_SHA1 签名函数,返回值为 HMAC_SHA1 加密后原始字节,而非16进制字符串,UTF_8_Encoding_Of() 是 UTF-8 字符编码函数,伪代码如下:
String signature = Base64(HMAC_SHA1(AccessSecret + "&", UTF_8_Encoding_Of(stringToSign)))
使用 HMAC-SHA1 签名算法,计算得到的公共参数 Signature 的签名值 signature
。
签名示例
本示例以调用 ECS DescribeDedicatedHosts查询一台或多台专有宿主机的详细信息为例。假设 AccessKeyID 为 testid, AccessKeySecret 为 testsecret,SignatureNonce 为 edb2b34af0af9a6d14deaf7c1a5315eb, Timestamp 为 2023-03-13T08:34:30Z,签名流程如下:
构造规范化请求字符串。
http://ecs.aliyuncs.com/?AccessKeyId=testid&Action=DescribeDedicatedHosts&Format=JSON&RegionId=cn-beijing&SignatureMethod=HMAC-SHA1&SignatureNonce=edb2b34af0af9a6d14deaf7c1a5315eb&SignatureVersion=1.0&Tag.1.Key=testkey&Tag.1.Value=testvalue&Timestamp=2023-03-13T08%3A34%3A30Z&Version=2014-05-26
构造待签名字符串
stringToSign
。GET&%2F&AccessKeyId%3Dtestid%26Action%3DDescribeDedicatedHosts%26Format%3DJSON%26RegionId%3Dcn-beijing%26SignatureMethod%3DHMAC-SHA1%26SignatureNonce%3Dedb2b34af0af9a6d14deaf7c1a5315eb%26SignatureVersion%3D1.0%26Tag.1.Key%3Dtestkey%26Tag.1.Value%3Dtestvalue%26Timestamp%3D2023-03-13T08%253A34%253A30Z%26Version%3D2014-05-26
计算签名值。例如
AccessKeySecret=testsecret
,用于计算的 Key 为testsecret&
(注意:加上后缀&)。计算得到的签名值为fRmq1o6saIIjVlawOy+o6jDU9JQ=
。伪代码如下:String Signature = Base64(HMAC_SHA1(AccessSecret + "&",UTF_8_Encoding_Of(stringToSign)))
得到完整的URL。添加RFC3986规则编码后的
Signature=fRmq1o6saIIjVlawOy%2Bo6jDU9JQ%3D
到第1步的 URL 中。https://ecs.cn-beijing.aliyuncs.com/?AccessKeyId=testid&Action=DescribeDedicatedHosts&Format=JSON&RegionId=cn-beijing&SignatureMethod=HMAC-SHA1&SignatureNonce=edb2b34af0af9a6d14deaf7c1a5315eb&SignatureVersion=1.0&Tag.1.Key=testkey&Tag.1.Value=testvalue&Timestamp=2023-03-13T08%3A34%3A30Z&Version=2014-05-26&Signature=fRmq1o6saIIjVlawOy%2Bo6jDU9JQ%3D
Version 字段值和域名是对应关系(服务域名和 Version 值请参看对应云产品 OpenAPI 云产品主页),错误的域名或 Version 值可能导致 InvalidVersion
错误。
通过第4步得到的 URL,您可以使用浏览器、curl 或者 wget 等工具发起HTTP请求调用DescribeDedicatedHosts
,查询一台或多台专有宿主机的详细信息。
附录
参数编码方式
在阿里云 OpenAPI 调用中,请求参数和参数值需使用 UTF-8 字符集按照RFC3986规则进行编码。具体编码规则如下:
字符 A~Z、a~z、0~9 以及字符
-
、_
、.
、~
不编码。对其他 ASCII 码字符进行编码。编码格式为%加上16进制的 ASCII 码。例如半角双引号(
"
)将被编码为%22
。非 ASCII 码通过 UTF-8 编码。
空格编码成
%20
,不使用加号(+
)表示空格。