腾讯云API:让你的代码更加稳定(Python版)

之前发了两个文章,是关于腾讯云API的使用的文章,主要是小Demo的展示,用来帮助初学者,或者最初使用者作为参考。但是有些人可能有疑问,或者新的想法,你这代码是否可以进行一些“黑科技”,当然可以。首先,上一下之前的两个代码:

腾讯云API:用Python使用腾讯云API(cvm实例)

腾讯云API:用Python使用腾讯云API(机器翻译实例)

那么,如果改进,应该如何改进呢?

1:云API官网有这样一段话

2.1. 对参数排序

首先对所有请求参数按参数名做字典序升序排列,所谓字典序升序排列,直观上就如同在字典中排列单词一样排序,按照字母表或数字表里递增顺序的排列次序,即先考虑第一个“字母”,在相同的情况下考虑第二个“字母”,依此类推。用户可以借助编程语言中的相关排序函数来实现这一功能,如php中的ksort函数。

这一段话就是说,我们的参数要进行相关排序,而我在之前发的代码中,是直接“人工手动“排序了,这样虽然可以在大部分机器运行,但是,因为Dict的无序性,可能还是会有无法运行的风险,所以,我们可以增加一个排序组合功能:

def signStrFun(dictData):
    '''
    本方法用来进行字典排序
    :param dictData:
    :return:
    '''
    tempList = []
    resultList = []
    for eveKey,eveValue in dictData.items():
        tempList.append(eveKey.lower())
    tempList.sort()
    for eveData in tempList:
        for eveKey, eveValue in dictData.items():
            if eveKey.lower() == eveData:
                tempStr = str(eveKey) + "=" + str(eveValue)
                resultList.append(tempStr)
    return "&".join(resultList)

这个代码的意思就是,传递进来一个字典类型的数据,然后将它进行Key的提取,然后进行lower操作,再进行sort操作,然后再从原来的Dict中获得结果,当然可以看到这里面有3个for,复杂度非常高!所以可以再次改进这个小功能:

def signStrFun(dictData):
    '''
    本方法用来进行字典排序
    :param dictData:
    :return:
    '''
    tempList = []
    resultList = []
    tempDict = {}
    for eveKey,eveValue in dictData.items():
        tempLowerData = eveKey.lower()
        tempList.append(tempLowerData)
        tempDict[tempLowerData] = eveKey
    tempList.sort()
    for eveData in tempList:
        tempStr = str(tempDict[eveData]) + "=" + str(dictData[tempDict[eveData]])
        resultList.append(tempStr)
    return "&".join(resultList)

这样一来,我们通过字典的映射,就可以更好地解决这个问题了。

当然,还有更好的解决方法,更好的解决方法在哪里呢?在SDK中,可以查看:https://cloud.tencent.com/document/sdk

新的CVM-Demo代码如下:

# -*- coding: utf-8 -*-

# 作者:Dfounderliu(刘宇)
# 程序功能:腾讯云API DEMO
# Python版本:python 3.0

# 可以在https://console.cloud.tencent.com/capi 获取

# 运行结果:
#  "Response": {
#         "TotalCount": *,
#         "InstanceSet": [
#             {
#                ******
#          ],
#          "RequestId": "***********"
#    }
#}

import binascii
import hashlib
import hmac
import sys
import urllib.parse
import urllib.request
import time
import random

def sign(secretKey, signStr, signMethod):
    '''
    该方法主要是实现腾讯云的签名功能
    :param secretKey: 用户的secretKey
    :param signStr: 传递进来字符串,加密时需要使用
    :param signMethod: 加密方法
    :return:
    '''
    if sys.version_info[0] > 2:
        signStr = signStr.encode("utf-8")
        secretKey = secretKey.encode("utf-8")

    # 根据参数中的signMethod来选择加密方式
    if signMethod == 'HmacSHA256':
        digestmod = hashlib.sha256
    elif signMethod == 'HmacSHA1':
        digestmod = hashlib.sha1

    # 完成加密,生成加密后的数据
    hashed = hmac.new(secretKey, signStr, digestmod)
    base64 = binascii.b2a_base64(hashed.digest())[:-1]

    if sys.version_info[0] > 2:
        base64 = base64.decode()

    return base64

def dictToStr(dictData):
    '''
    本方法主要是将Dict转为List并且拼接成字符串
    :param dictData:
    :return: 拼接好的字符串
    '''
    tempList = []
    for eveKey, eveValue in dictData.items():
        tempList.append(str(eveKey) + "=" + str(eveValue))
    return "&".join(tempList)

def signStrFun(dictData):
    '''
    本方法用来进行字典排序
    :param dictData:
    :return:
    '''
    tempList = []
    resultList = []
    tempDict = {}
    for eveKey,eveValue in dictData.items():
        tempLowerData = eveKey.lower()
        tempList.append(tempLowerData)
        tempDict[tempLowerData] = eveKey
    tempList.sort()
    for eveData in tempList:
        tempStr = str(tempDict[eveData]) + "=" + str(dictData[tempDict[eveData]])
        resultList.append(tempStr)
    return "&".join(resultList)

# 用户必须准备好的secretId和secretKey
# 可以在 https://console.cloud.tencent.com/capi 获取
secretId = "你的secretId"
secretKey = "你的secretKey"

# 在此处定义一些必须的内容
timeData = str(int(time.time())) # 时间戳
nonceData = int(random.random()*10000) # Nonce,官网给的信息:随机正整数,与 Timestamp 联合起来, 用于防止重放攻击
actionData = "DescribeInstances" # Action一般是操作名称
uriData = "cvm.tencentcloudapi.com" # uri,请参考官网
signMethod="HmacSHA256" # 加密方法
requestMethod = "GET" # 请求方法,在签名时会遇到,如果签名时使用的是GET,那么在请求时也请使用GET
regionData = "ap-hongkong" # 区域选择
versionData = '2017-03-12' # 版本选择

# 签名时需要的字典
# 首先对所有请求参数按参数名做字典序升序排列,所谓字典序升序排列,
# 直观上就如同在字典中排列单词一样排序,按照字母表或数字表里递增
# 顺序的排列次序,即先考虑第一个“字母”,在相同的情况下考虑第二
# 个“字母”,依此类推。
signDictData = {
    'Action' : actionData,
    'Nonce' : nonceData,
    'Region' : regionData,
    'SecretId' : secretId,
    'SignatureMethod':signMethod,
    'Timestamp' : int(timeData),
    'Version':versionData ,
}

# 获得拼接的字符串,用于签名
# 此步骤生成请求字符串。 将把上一步排序好的请求参数格式化成“参数名称”=“参数值”的形式,如对Action参数,
# 其参数名称为"Action",参数值为"DescribeInstances",因此格式化后就为Action=DescribeInstances。
# 注意:“参数值”为原始值而非url编码后的值。
# 然后将格式化后的各个参数用"&"拼接在一起,最终生成请求字符串。
# 此步骤生成签名原文字符串。 签名原文字符串由以下几个参数构成:
# 1) 请求方法: 支持 POST 和 GET 方式,这里使用 GET 请求,注意方法为全大写。
# 2) 请求主机:查看实例列表(DescribeInstances)的请求域名为:cvm.tencentcloudapi.com。实际的请求域名根据接口所属模块的不同而不同,详见各接口说明。
# 3) 请求路径: 当前版本云API的请求路径固定为 / 。 4) 请求字符串: 即上一步生成的请求字符串。
# 签名原文串的拼接规则为:
#   请求方法 + 请求主机 +请求路径 + ? + 请求字符串
requestStr = "%s%s%s%s%s"%(requestMethod,uriData,"/","?",signStrFun(signDictData))

# 调用签名方法,同时将结果进行url编码,官方文档描述如下:
# 生成的签名串并不能直接作为请求参数,需要对其进行 URL 编码。 注意:如果用户的请求方法是GET,则对所有请求参
# 数值均需要做URL编码。 如上一步生成的签名串为 EliP9YW3pW28FpsEdkXt/+WcGeI= ,最终得到的签名串请求参数(Signature)
# 为: EliP9YW3pW28FpsEdkXt%2f%2bWcGeI%3d ,它将用于生成最终的请求URL。
signData = urllib.parse.quote(sign(secretKey,requestStr,signMethod))

# 上述操作是实现签名,下面即进行请求
# 先建立请求参数, 此处参数只在签名时多了一个Signature
actionArgs = signDictData
actionArgs["Signature"] = signData

# 根据uri构建请求的url
requestUrl = "https://%s/?"%(uriData)
# 将请求的url和参数进行拼接
requestUrlWithArgs = requestUrl + dictToStr(actionArgs)

# 获得response
responseData = urllib.request.urlopen(requestUrlWithArgs).read().decode("utf-8")

print(responseData)

# 获得到的结果形式:
#  "Response": {
#         "TotalCount": *,
#         "InstanceSet": [
#             {
#                ******
#          ],
#          "RequestId": "***********"
#    }
#}

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏知了

ijst:基于反射的 C++ JSON 反序列化库

ijst (iJsonStruct) 一个是 C++ Json 序列化/反序列化库:

2625
来自专栏我有一个梦想

QT Creator 快速入门教程 读书笔记(三)

一   信号和槽   GUI 程序除了要绘制控件,还要响应系统和用户事件,例如重绘、绘制完成、点击鼠标、敲击键盘等。当事件发生时,UI 会产生相应的变化,让用户...

2608
来自专栏一个番茄说

让你在WebView中用JS调Native Object

之所做这个东西,源于之前项目中需要把一些页面用webView来呈现,但是web中需要调用native的方法,比如获取本地存的某些数据、调用摄像头等等,这里也就是...

1003
来自专栏程序员的SOD蜜

PostgreSQL的.NET驱动程序Npgsql中参数对象的一个Bug

最近将公司的项目从SqlServer移植到PostgreSQL数据库上来,在调用数据库的存储过程(自定义函数)的时候,发现一个奇怪的问题,老是报函数无法找到。 ...

2867
来自专栏difcareer的技术笔记

Android Linker学习笔记[转]

Linker是Android系统动态库so的加载器/链接器,要想轻松地理解Android linker的运行机制,我们需要先熟悉ELF的文件结构,再了解ELF文...

2394
来自专栏安恒网络空间安全讲武堂

nox&CSAW部分pwn题解

暑假的时候遇到了一群一起学习安全的小伙伴,在他们的诱劝下,开始接触国外的CTF比赛,作为最菜的pwn选手就试着先打两场比赛试试水,结果发现国外比赛真有意思哎嘿。

1613
来自专栏IT 指南者专栏

Spring框架系列之AOP思想

微信公众号:compassblog 欢迎关注、转发,互相学习,共同进步! 有任何问题,请后台留言联系! 1、AOP概述 (1)、什么是 AOP AOP 为 As...

3427
来自专栏Spark生态圈

[spark] 内存管理 MemoryManager 解析

spark的内存管理有两套方案,新旧方案分别对应的类是UnifiedMemoryManager和StaticMemoryManager。

2312
来自专栏Scott_Mr 个人专栏

RxSwift 系列(九) -- 那些难以理解的概念

4987
来自专栏Java学习网

Java Web Response对象的27个方法及状态码

response表示HttpServletResponse对象,主要将JSP容器处理后的结果传回到客户端。 ? 网络配图 1、void addCookie(...

3207

扫码关注云+社区