秋栈博客

七月

使用Golang写一段接口请求代码。

3
2023-02-10
 

使用Golang写一段接口请求代码。

需求举例

比如我们在飞书自建了一个机器人应用,我需要通过获取它的tenant_access_token去对成员或群组发送消息。
飞书官网文档地址: https://open.feishu.cn/document/ukTMukTMukTM/ukDNz4SO0MjL5QzM/auth-v3/auth/tenant_access_token_internal 举个栗子,下面是一段curl形式的post请求:
curl --location --request POST 'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-raw '{
    "app_id":"cli_a3a6aa8193bc5013",
    "app_secret":"qpLb4xUS7L9UGegfzwSiAbaPU1xiPI8T"
}'
调用成功后返回的json响应体:
{
    "code": 0,
    "expire": 7200,
    "msg": "ok",
    "tenant_access_token": "t-g1042fglZNOKOZCQZBI77M62OUJSRG3LP4F6CW4V"
}
如何用Go去写这样一个post请求? 以这段请求举例:
  • --location:如果服务器返回了301或302则会从服务器接收一个新的URL地址,以防变更。
  • --request:请求类型为POST
  • --header:请求头
  • --data-raw:请求体
我们需要传入我们的请求体。

首先转换格式

我们可以通过一些现成的工具去帮我们做转换。

1、Curl To Go

这个网站不同的是会把你的curl请求直接转换为一段Go的示例代码。 网站地址:https://mholt.github.io/curl-to-go/ 示例:  

2、Json To Go

我最常用的是这个工具。 网站地址:https://mholt.github.io/json-to-go/ 示例: 于是我们可以得到转换后的结构体:
type MsgBack struct {
	Code              int    `json:"code"`
	Expire            int    `json:"expire"`
	Msg               string `json:"msg"`
	TenantAccessToken string `json:"tenant_access_token"`
}

type MsgSend struct {
	AppID     string `json:"app_id"`
	AppSecret string `json:"app_secret"`
}

在方法中使用

使用键值对初始化:
data := MsgSend{
	AppID:     "cli_a3a6aa8193bc5013",
	AppSecret: "qpLb4xUS7L9UGegfzwSiAbaPU1xiPI8T",
}
将数据结构转换为json字符串,NewReader方法区读取字符串作为请求体:
b, err := json.Marshal(data)
payload := strings.NewReader(string(b))
发起一个POST请求:
url := "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal"
method := "POST"

b, err := json.Marshal(data)
payload := strings.NewReader(string(b))

client := &http.Client{}
req, err := http.NewRequest(method, url, payload)
if err != nil {
	fmt.Println(err)
	return
}

req.Header.Add("Content-Type", "application/json; charset=utf-8")

res, err := client.Do(req)
if err != nil {
	fmt.Println(err)
	return
}
在函数返回之前调用Body.Close()方法关闭资源。
defer func(Body io.ReadCloser) {
	err := Body.Close()
	if err != nil {
		fmt.Println(err)
	}
}(res.Body)
将res.Body中的内容读取到一个字节切片中,并将字节切片赋值给body。
body, err := ioutil.ReadAll(res.Body)
if err != nil {
	fmt.Println(err)
	return
}
实例化MsgBack结构体,将body中的json数据解析到msg结构体中。
var msg MsgBack
err = json.Unmarshal(body, &msg)
if err != nil {
	fmt.Println(err)
	return
}
判断是否调用成功。
if msg.Code != 0 {
	fmt.Println(msg.Msg)
	return
}
fmt.Println(msg.TenantAccessToken)

测试

# 测试调用成功,返回结构体MsgBack中的tenant_access_token参数
$ go run main.go
t-g1042fglZNOKOZCQZBI77M62OUJSRG3LP4F6CW4V
# 测试调用失败,返回结构体MsgBack中的msg参数
$ go run main.go
app id not exists

完整代码

package main

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
)

type MsgBack struct {
	Code              int    `json:"code"`
	Expire            int    `json:"expire"`
	Msg               string `json:"msg"`
	TenantAccessToken string `json:"tenant_access_token"`
}
type MsgSend struct {
	AppID     string `json:"app_id"`
	AppSecret string `json:"app_secret"`
}

func main() {
	data := MsgSend{
		AppID:     "cli_a3a6aa8193bc5013",
		AppSecret: "qpLb4xUS7L9UGegfzwSiAbaPU1xiPI8T",
	}

	url := "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal"
	method := "POST"

	b, err := json.Marshal(data)
	payload := strings.NewReader(string(b))

	client := &http.Client{}
	req, err := http.NewRequest(method, url, payload)
	if err != nil {
		fmt.Println(err)
		return
	}

	req.Header.Add("Content-Type", "application/json; charset=utf-8")

	res, err := client.Do(req)
	if err != nil {
		fmt.Println(err)
		return
	}

	defer func(Body io.ReadCloser) {
		err := Body.Close()
		if err != nil {
			fmt.Println(err)
		}
	}(res.Body)

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		fmt.Println(err)
		return
	}

	var msg MsgBack
	err = json.Unmarshal(body, &msg)
	if err != nil {
		fmt.Println(err)
		return
	}
	//判断是否成功
	if msg.Code != 0 {
		fmt.Println(msg.Msg)
		return
	}
	fmt.Println(msg.TenantAccessToken)
}
 
  • 0