二丫讲梵 二丫讲梵
首页
  • 最佳实践
  • 迎刃而解
  • Nginx
  • Php
  • Zabbix
  • AWS
  • Prometheus
  • Grafana
  • CentOS
  • Systemd
  • Docker
  • Rancher
  • Ansible
  • Ldap
  • Gitlab
  • GitHub
  • Etcd
  • Consul
  • RabbitMQ
  • Kafka
  • MySql
  • MongoDB
  • OpenVPN
  • KVM
  • VMware
  • Other
  • ELK
  • K8S
  • LLM
  • Nexus
  • Jenkins
  • 随写编年
  • 家人物语
  • 追忆青春
  • 父亲的朋友圈
  • 电影音乐
  • 效率工具
  • 博客相关
  • Shell
  • 前端实践
  • Vue学习笔记
  • Golang学习笔记
  • Golang编程技巧
  • 学习周刊
  • Obsidian插件周刊
关于
友链
  • 本站索引

    • 分类
    • 标签
    • 归档
  • 本站页面

    • 导航
    • 打赏
  • 我的工具

    • 备忘录清单 (opens new window)
    • json2go (opens new window)
    • gopher (opens new window)
    • 微信MD编辑 (opens new window)
    • 国内镜像 (opens new window)
    • 出口IP查询 (opens new window)
    • 代码高亮工具 (opens new window)
  • 外站页面

    • 开往 (opens new window)
    • ldapdoc (opens new window)
    • HowToStartOpenSource (opens new window)
    • vdoing-template (opens new window)
GitHub (opens new window)

二丫讲梵

行者常至,为者常成
首页
  • 最佳实践
  • 迎刃而解
  • Nginx
  • Php
  • Zabbix
  • AWS
  • Prometheus
  • Grafana
  • CentOS
  • Systemd
  • Docker
  • Rancher
  • Ansible
  • Ldap
  • Gitlab
  • GitHub
  • Etcd
  • Consul
  • RabbitMQ
  • Kafka
  • MySql
  • MongoDB
  • OpenVPN
  • KVM
  • VMware
  • Other
  • ELK
  • K8S
  • LLM
  • Nexus
  • Jenkins
  • 随写编年
  • 家人物语
  • 追忆青春
  • 父亲的朋友圈
  • 电影音乐
  • 效率工具
  • 博客相关
  • Shell
  • 前端实践
  • Vue学习笔记
  • Golang学习笔记
  • Golang编程技巧
  • 学习周刊
  • Obsidian插件周刊
关于
友链
  • 本站索引

    • 分类
    • 标签
    • 归档
  • 本站页面

    • 导航
    • 打赏
  • 我的工具

    • 备忘录清单 (opens new window)
    • json2go (opens new window)
    • gopher (opens new window)
    • 微信MD编辑 (opens new window)
    • 国内镜像 (opens new window)
    • 出口IP查询 (opens new window)
    • 代码高亮工具 (opens new window)
  • 外站页面

    • 开往 (opens new window)
    • ldapdoc (opens new window)
    • HowToStartOpenSource (opens new window)
    • vdoing-template (opens new window)
GitHub (opens new window)
  • Shell编程

  • Go编程笔记

    • 开发技巧

      • go日常开发代码片段
      • golang交叉编译
      • 两个切片内容相减的几种方法
      • golang以结构体中某个字段进行排序
      • vscode开发golang报黄提示composite literal uses unkeyed fields
      • golang使用$in或$nin查询MongoDB是否在数组内的数据
      • golang使用$push和$addToSet往数组添加字段的异同
      • MongoDB自增ID在golang中的实践
      • golang数据类型转换汇总
      • 记录VSCode中写Go代码切换Sqlite无CGO依赖版本的过程以及遇到的五个问题
      • 企业微信自建应用-golang校验回调
      • 对接腾讯云未集成到SDK的接口开发实践小记
        • 前言
        • 认识原生请求方法
        • 集成官方提供的方法
        • 如何快速找到接口
      • Go开发实践之Gin框架将前端的dist目录embed到二进制
    • 库包研究

    • 个人项目

  • 前端编程笔记

  • Go学习笔记

  • Vue-21年学习笔记

  • Vue-22年重学笔记

  • 编程世界
  • Go编程笔记
  • 开发技巧
二丫讲梵
2024-03-18
目录

对接腾讯云未集成到SDK的接口开发实践小记

文章发布较早,内容可能过时,阅读注意甄别。

# 前言

日常工作中,与腾讯云打交道,为了提高效率,会调用它的接口来完成一些重复性工作。一般都是通过官方集成好的 SDK 来完成交互。

但有时候也存在一种情况,那就是这个接口还没有集成到 SDK 当中,又需要进行调用,此时可通过原生方式生成 curl 请求,以达到调用目的。

本文记录如何快速实现并完成这样一个流程,以此记录,便于后续再次查阅。

# 认识原生请求方法

通常在每个产品的 API 接口文档页面,都会在调用方式里边有一个 签名方法 v3 的页面,在这个页面,介绍了如何自助生成签名,完成接口的调用。

这里以云服务器的签名方法 v3 (opens new window) 的文档介绍为例,来简单认识一下这一思路的用法。

我这里选择其中提供的 Golang 代码示例来做演示:

package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "fmt"
    "os"
    "strings"
    "time"
)

func sha256hex(s string) string {
    b := sha256.Sum256([]byte(s))
    return hex.EncodeToString(b[:])
}

func hmacsha256(s, key string) string {
    hashed := hmac.New(sha256.New, []byte(key))
    hashed.Write([]byte(s))
    return string(hashed.Sum(nil))
}

func main() {
    // 需要设置环境变量 TENCENTCLOUD_SECRET_ID,值为示例的 AKIDz8krbsJ5yKBZQpn74WFkmLPx3*******
    secretId := os.Getenv("TENCENTCLOUD_SECRET_ID")
    // 需要设置环境变量 TENCENTCLOUD_SECRET_KEY,值为示例的 Gu5t9xGARNpq86cd98joQYCN3*******
    secretKey := os.Getenv("TENCENTCLOUD_SECRET_KEY")
    host := "cvm.tencentcloudapi.com"
    algorithm := "TC3-HMAC-SHA256"
    service := "cvm"
    version := "2017-03-12"
    action := "DescribeInstances"
    region := "ap-guangzhou"
    //var timestamp int64 = time.Now().Unix()
    var timestamp int64 = 1551113065

    // step 1: build canonical request string
    httpRequestMethod := "POST"
    canonicalURI := "/"
    canonicalQueryString := ""
    canonicalHeaders := fmt.Sprintf("content-type:%s\nhost:%s\nx-tc-action:%s\n",
        "application/json; charset=utf-8", host, strings.ToLower(action))
    signedHeaders := "content-type;host;x-tc-action"
    payload := `{"Limit": 1, "Filters": [{"Values": ["\u672a\u547d\u540d"], "Name": "instance-name"}]}`
    hashedRequestPayload := sha256hex(payload)
    canonicalRequest := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s",
        httpRequestMethod,
        canonicalURI,
        canonicalQueryString,
        canonicalHeaders,
        signedHeaders,
        hashedRequestPayload)
    fmt.Println(canonicalRequest)

    // step 2: build string to sign
    date := time.Unix(timestamp, 0).UTC().Format("2006-01-02")
    credentialScope := fmt.Sprintf("%s/%s/tc3_request", date, service)
    hashedCanonicalRequest := sha256hex(canonicalRequest)
    string2sign := fmt.Sprintf("%s\n%d\n%s\n%s",
        algorithm,
        timestamp,
        credentialScope,
        hashedCanonicalRequest)
    fmt.Println(string2sign)

    // step 3: sign string
    secretDate := hmacsha256(date, "TC3"+secretKey)
    secretService := hmacsha256(service, secretDate)
    secretSigning := hmacsha256("tc3_request", secretService)
    signature := hex.EncodeToString([]byte(hmacsha256(string2sign, secretSigning)))
    fmt.Println(signature)

    // step 4: build authorization
    authorization := fmt.Sprintf("%s Credential=%s/%s, SignedHeaders=%s, Signature=%s",
        algorithm,
        secretId,
        credentialScope,
        signedHeaders,
        signature)
    fmt.Println(authorization)

    curl := fmt.Sprintf(`curl -X POST https://%s\
 -H "Authorization: %s"\
 -H "Content-Type: application/json; charset=utf-8"\
 -H "Host: %s" -H "X-TC-Action: %s"\
 -H "X-TC-Timestamp: %d"\
 -H "X-TC-Version: %s"\
 -H "X-TC-Region: %s"\
 -d '%s'`, host, authorization, host, action, timestamp, version, region, payload)
    fmt.Println(curl)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92

如上命令运行之后,最后会打印该 curl 请求如下:

$ curl -X POST https://cvm.tencentcloudapi.com\
 -H "Authorization: TC3-HMAC-SHA256 Credential=***EG1Yac266rMcU6uZO****AhzRdZaRqMRG/2019-02-25/cvm/tc3_request, SignedHeaders=content-type;host;x-tc-action, Signature=b**cc7cd1c906c828ba52266b543816adf61a6df9af2e4da708fb790"\
 -H "Content-Type: application/json; charset=utf-8"\
 -H "Host: cvm.tencentcloudapi.com" -H "X-TC-Action: DescribeInstances"\
 -H "X-TC-Timestamp: 1551113065"\
 -H "X-TC-Version: 2017-03-12"\
 -H "X-TC-Region: ap-guangzhou"\
 -d '{"Limit": 1, "Filters": [{"Values": ["\u672a\u547d\u540d"], "Name": "instance-name"}]}'
1
2
3
4
5
6
7
8

整个代码里边每个步骤的操作也都有注释,就不一一解释了。这里简单概述一下,如上代码,除去生成签名的步骤之外,还有五个部分,来完成此命令的渲染:

  • host: 指定要请求的域名地址。
  • service: 指定服务类型
  • version::指定接口版本
  • action::指定请求的动作,即对应的接口
  • region::指定资源的区域
  • payload::指定请求的参数

# 集成官方提供的方法

如上方法对应的代码,一大块儿都是签名的处理,猛地一看这些代码,可能也很懵,我一开始还想着如何简化抽象一下签名的方法,就在简化的过程中,一检索,发现,事实上官方的 SDK 也提供了简化的方案。

比如 golang 的 SDK,看官方 readme,有专门的介绍:结合 common client 自定义请求 (opens new window)。

其中也提供了代码示例:

package main

import (
	"fmt"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
	tchttp "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/regions"
	"log"
	"os"
)

// 目前只支持 签名v3+POST
func main() {
	credential := common.NewCredential(
		os.Getenv("TENCENTCLOUD_SECRET_ID"),
		os.Getenv("TENCENTCLOUD_SECRET_KEY"))
	cpf := profile.NewClientProfile()
	cpf.HttpProfile.Endpoint = "cvm.tencentcloudapi.com"
	cpf.HttpProfile.ReqMethod = "POST"
	//创建common client
	client := common.NewCommonClient(credential, regions.Guangzhou, cpf).WithLogger(log.Default())

	// 创建common request,依次传入产品名、产品版本、接口名称
	request := tchttp.NewCommonRequest("cvm", "2017-03-12", "DescribeZones")

	// 自定义请求参数:
	// SetActionParameters 函数支持三种数据类型的入参:
	// 1. map[string]interface{}
	// body:=map[string]interface{}{
	// "InstanceId":"crs-xxx",
	// "SpanType":2,
	// }
	body := map[string]interface{}{}

	// // 2. string
	// bodyStr := `{}`

	// // 3. []byte
	// bodyBytes := []byte(bodyStr)

	// set custom headers
	request.SetHeader(map[string]string{
		"X-TC-TraceId": "ffe0c072-8a5d-4e17-8887-a8a60252abca",
	})

	// 设置action所需的请求数据
	err := request.SetActionParameters(body)
	if err != nil {
		return
	}

	//创建common response
	response := tchttp.NewCommonResponse()

	//发送请求
	err = client.Send(request, response)
	if err != nil {
		fmt.Printf("fail to invoke api: %v \n", err)
	}

	// 获取响应结果
	fmt.Println(string(response.GetBody()))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

借助于官方封装好的 client,就可以直接拼装接口,完成调用了。

这里贴一个自己封装的,将 MySQL 实例设置为只读的方法,以供参考:

// SetCdbReadOnly 设置cdb实例只读 0:只读 1:读写
func SetCdbReadOnly(credential *common.Credential, instanceid string, readonly int) (*tchttp.CommonResponse, error) {
	cpf := profile.NewClientProfile()
	cpf.HttpProfile.Endpoint = "cdb.tencentcloudapi.com"
	client := common.NewCommonClient(credential, regions.Shanghai, cpf).WithLogger(log.Default())

	request := tchttp.NewCommonRequest("cdb", "2017-03-20", "ModifyDBInstanceReadOnlyStatus")
	body := map[string]interface{}{
		"InstanceId": instanceid,
		"ReadOnly":   readonly,
	}
	err := request.SetActionParameters(body)
	if err != nil {
		return nil, err
	}
	response := tchttp.NewCommonResponse()
	err = client.Send(request, response)
	if err != nil {
		return nil, err
	}

	return response, nil
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

如此一来,要想自定义封装一些尚未集成到 SDK 的方法,就变得比较简单了。

# 如何快速找到接口

很多时候,一些相对偏门的接口,可能第一步困难的是如何找到这个接口相关的文档说明,这里也记录一下我个人的一些心得。

方法一:

通过自己的渠道,直接找到腾讯云官方的人员,咨询对应的接口,这是最高效也是最可靠的方式。

方法二:

  • 通过腾讯云 API 平台检索,点我跳转。 (opens new window)
  • 或者通过 API Inspector 找到对应接口,点我看相关介绍 (opens new window)。
  • 如果上边两种方案都不行,那就只能 F12 通过点击页面,生看生撸接口了。
微信 支付宝
上次更新: 2024/09/26, 21:41:44
企业微信自建应用-golang校验回调
Go开发实践之Gin框架将前端的dist目录embed到二进制

← 企业微信自建应用-golang校验回调 Go开发实践之Gin框架将前端的dist目录embed到二进制→

最近更新
01
学习周刊-总第213期-2025年第22周
05-29
02
学习周刊-总第212期-2025年第21周
05-22
03
从赵心童世锦赛夺冠聊聊我的斯诺克情缘
05-16
更多文章>
Theme by Vdoing | Copyright © 2017-2025 | 点击查看十年之约 | 浙ICP备18057030号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式