## **创建规范请求**
要开始签名过程,请创建一个字符串,其中包含来自标准(规范)格式的请求的信息。这可确保 GSDATA 在收到请求时计算出的签名与您计算出的签名相同。
按照此处的步骤创建请求的规范版本。否则,您的版本与 GSDATA 计算得到的版本将不匹配,请求将被拒绝。
以下示例演示了创建规范请求的伪代码。
**例 规范请求伪代码**
~~~
CanonicalRequest =
HTTPRequestMethod + '\n' +
CanonicalURI + '\n' +
CanonicalQueryString + '\n' +
CanonicalHeaders + '\n' +
SignedHeaders + '\n' +
HexEncode(Hash(RequestPayload))
~~~
在此伪代码中,Hash 表示生成消息摘要的函数,通常是 SHA-256。(在该过程中的稍后阶段,您将指定要使用的哈希算法。)HexEncode 表示以小写字母形式返回摘要的 base-16 编码的函数。例如,HexEncode("m") 返回值 6d 而不是 6D。输入的每一个字节都必须表示为两个十六进制字符,java版本HexEncode。
以下示例演示如何构造规范形式的 API 请求。原始请求在从客户端发送到 GSDATA 时可能看上去与此类似,不过此示例还不包括签名信息。
~~~
GET http://api.gsdata.cn/weixin/v1/users?wx_name=rmrbwx&page=1&per-page=20 HTTP/1.1
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Host: api.gsdata.cn
x-gsdata-date: 20150830T123600Z
~~~
**要创建规范请求,请将以下来自每个步骤的部分连接为一个字符串:**
1. 首先是 HTTP 请求方法(GET、PUT、POST 等),后跟换行符。
**例 示例请求方法**
~~~
GET
~~~
2. 添加规范 URI 参数,后跟换行符。规范 URI 是 URI 的绝对路径部分的 URI 编码版本,该版本是 URI 中的一切 - 从 HTTP 主机到开始查询字符串参数(如果有)的问号字符(“?”)。
根据 RFC 3986 标准化 URI 路径。移除冗余和相对路径部分。路径中每个部分都必须为 URI 编码。
3. 添加规范查询字符串,后跟换行符。如果请求不包括查询字符串,请使用空字符串(实际上是空白行)。示例请求具有以下查询字符串。
**例 规范查询字符串示例**
~~~
Action=ListUsers&Version=2010-05-08
~~~
要构建规范查询字符串,请完成以下步骤:
1). 按字符代码点以升序顺序对参数名称进行排序。例如,以大写字母 F 开头的参数名称排在以小写字母 b 开头的参数名称之前。
2). 根据以下规则对每个参数名称和值进行 URI 编码:
* 请勿对 RFC 3986 定义的任何非预留字符进行 URI 编码,这些字符包括:A-Z、a-z、0-9、连字符 (-)、下划线 (_)、句点 (.) 和波浪符 ( ~ )。
* 使用 %XY 对所有其他字符进行百分比编码,其中“X”和“Y”为十六进制字符(0-9 和大写字母 A-F)。例如,空格字符必须编码为 %20(不像某些编码方案那样使用“+”),扩展 UTF-8 字符必须采用格式 %XY%ZA%BC。
3). 以排序后的列表中第一个参数名称开头,构造规范查询字符串。
4). 对于每个参数,追加 URI 编码的参数名称,后跟等号字符 (=),再接 URI 编码的参数值。对没有值的参数使用空字符串。
5). 在每个参数值后追加与字符 (&),列表中最后一个值除外。
4. 添加规范标头,后跟换行符。规范标头包括您要包含在签名请求中的所有 HTTP 标头的列表。
您必须至少包含 host 标头。标准标头(如 content-type)是可选的。不同的服务可能需要其他标头。
**例 规范标头示例**
~~~
content-type:application/x-www-form-urlencoded; charset=utf-8\n
host:api.gsdata.cn\n
x-gsdata-date:20170620T123600Z\n
~~~
要创建规范标头列表,请将所有标头名称转换为小写形式并删除前导空格和尾随空格。将标头值中的连续空格转换为单个空格。
以下伪代码描述如何构造规范标头列表:
~~~
CanonicalHeaders =
CanonicalHeadersEntry0 + CanonicalHeadersEntry1 + ... + CanonicalHeadersEntryN
CanonicalHeadersEntry =
Lowercase(HeaderName) + ':' + Trimall(HeaderValue) + '\n'
~~~
Lowercase 表示将所有字符转换为小写字母的函数。Trimall 函数删除值前后的多余空格并将连续空格转换为单个空格。
通过按字符代码对(小写)标头排序,然后对标头名称进行迭代操作,来构建规范标头列表。根据以下规则构造每个标头:
追加小写标头名称,后跟冒号。
追加该标头的值的逗号分隔列表。请勿对有多个值的标头进行值排序。
追加一个新行(“\n”)。
5. 添加已签名的标头,后跟换行符。该值是您包含在规范标头中的标头列表。通过添加此标头列表,您可以向 GSDATA 告知请求中的哪些标头是签名过程的一部分以及在验证请求时 GSDATA 可以忽略哪些标头(例如,由代理添加的任何附加标头)。
host 标头必须作为已签名标头包括在内。如果包括日期或 x-gsdata-date 标头,则还必须包括在已签名标头列表中的标头。
要创建已签名标头列表,请将所有标头名称转换为小写形式,按字符代码对其进行排序,并使用分号来分隔这些标头名称。以下伪代码描述如何构建已签名标头的列表。Lowercase 表示将所有字符转换为小写字母的函数。
通过对按小写字符代码排序的标头名称集合进行迭代操作,构建已签名标头的列表。对于除最后一个标头外的每个标头名称,请在标头名称后追加分号(“;”),将它与后面的标头名称分隔开。
6. 使用 SHA256 等哈希 (摘要) 函数以基于 HTTP 或 HTTPS 请求正文中的负载创建哈希值。签名需要您使用UTF-8字符编码来对负载中的文本进行编码。
在创建待签字符串后,请指定用于对负载进行哈希(SHA256)处理的签名算法。指定 GSDATA-HMAC-SHA256 作为签名算法。经过哈希处理的负载必须以小写十六进制字符串形式表示。
如果负载为空,则使用空字符串作为哈希函数的输入。
7. 要构建完整的规范请求,请将来自每个步骤的所有组成部分组合为单个字符串。如上所述,每个组成部分都以换行符结尾。如果您执行前述规范请求伪代码,生成的规范请求将显示在以下示例中。
8. 使用您对负载进行哈希处理时所使用的相同算法来创建规范请求的摘要(哈希)。