赞
踩
以前工作中写脚本访问阿里云的资源时,都是通过调用系统命令(调用CLI工具)的方式,这次尝试通过http请求来实现想要的操作。
本次实现中遇到的问题:
1、向api发送请求是总是返回报错:Specified parameter Version is not valid,从报错上看是参数中设置的Version的值有问题,但反复核实请求中带的Version并没有问题。
解决方法:如果你遇到同样的问题,估计跟我一样,构建好请求url后,在向api发送请求时也是以调用系统命令(curl)的方式来实现的,这里要把请求的url用引号引起来,形式如下:cmd = "curl ‘http://xxx.example.com?Aciton=XXXX&…’ ",具体为什,据说是因为url中的&符号,是一个命令行执行后台挂起的标志,导致curl命令执行与预期不符,我并没有去验证,大体上应该就是这么回事了
2、在解决了上一个问题后,再次发送请求,返回结果为:errorCode:IncompleteSignature,msg:“The request signature does not conform to Aliyun standards.”
解决方法:报错很明显是计算得到的签名Signature有问题,问题出在待签名字符串上,待签名字符串中的参数部分,我只对它进行了一次urlencode操作,还需要再进行一次percentEncode操作,将其中的等号“=”,编码成%3D
下面记录一下代码的实现,学过的东西还是要多复习,毕竟编码经验还不纯熟。(我安装的是python3.7的版本)
用法:aliyunTool.py -f params.json
params.json示例:
{ "endpoint": "https://ecs.aliyuncs.com", "AccessKeyId": "xxxxxxxxxxxxxxxxxxxxxxx", "AccessKeySecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxx", "Params": { "AccessKeyId": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "Format": "json", "Version": "2014-05-26", "SignatureMethod": "HMAC-SHA1", "Timestamp": "", "SignatureVersion": "1.0", "SignatureNonce": "", "Action": "DescribeInstances", "RegionId": "cn-beijing", "PageSize": "50" } }
代码示例,复制可直接使用:
import datetime import urllib.request import urllib.parse import hmac import base64 import json import uuid import argparse import copy def getConfigFromFile(configFile): config_file = open(configFile) config = json.load(config_file) config_file.close() # 计算时间戳参数,使用的是utc时间,并格式化成指定的格式 return config def requestByConfig(config): #计算时间戳参数,使用的是utc时间,并格式化成指定的格式 timestamp = datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ") #下面三个参数要求全局唯一,使用uuid生成随机字符串 #ClientToken = str(uuid.uuid4()) #本示例中用不到 #Token = str(uuid.uuid4()) #本示例中用不到 signatureNonce = str(uuid.uuid4()) #下面根据阿里云文档计算待签名字符串 #def generateToSignStr(commonparams,customparams): #首先合并公共参数和自定义参数,然后排序 params = copy.copy(config["Params"]) params["Timestamp"] = timestamp params["SignatureNonce"] = signatureNonce sortedParams = sorted(params.items(), key=lambda x: x[0]) #然后对合并排序后的参数进行urlencode编码,得到的是多个key=value的键值对通过&符号连接后组成的字符串 urlencodeParams = urllib.parse.urlencode(sortedParams).replace("+","%20").replace("*","%2A").replace("%7E","~") #再处理一次,将urlencode后的字符串中的“=”和“&”进行percent编码 urlencodeParams = urllib.parse.quote_plus(urlencodeParams) #最后生成待签名字符串 toSignStr = "GET"+"&"+urllib.parse.quote_plus("/")+"&"+urlencodeParams #计算签名 h = hmac.new((config["AccessKeySecret"]+"&").encode(),toSignStr.encode(),"sha1") signature = base64.encodebytes(h.digest()).strip().decode() #将Signature添加到请求参数,生成请求url params["Signature"] = signature url = config["endpoint"]+"?"+urllib.parse.urlencode(params).replace("+","%20") print(url) #发送请求并打印结果 res=None try: response = urllib.request.urlopen(url) # 先将结果转换成字典,再转换成json对象,格式化输出 res = json.load(response) # print(json.dumps(res, sort_keys=True, indent=2)) return res except IOError as e: print(e.read()) if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument("-f", "--conf", type=str, default="config.json", help="请求接口的配置及参数的配置文件") args = parser.parse_args() conf = getConfigFromFile(args.conf) x = requestByConfig(conf) print(x) params = { "endpoint": "https://ecs.aliyuncs.com", "AccessKeyId": "xxxxxxxxxxxxxxxxxxxxxxx", "AccessKeySecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxx", "Params": { "AccessKeyId": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "Format": "json", "Version": "2014-05-26", "SignatureMethod": "HMAC-SHA1", "Timestamp": "", "SignatureVersion": "1.0", "SignatureNonce": "", "Action": "DescribeInstances", "RegionId": "cn-beijing", "PageSize": "50" } } y = requestByConfig(params) print(y)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。