使用Golang向NCMB发送请求

NCMB提供了针对各种语言的SDK。如果考虑非官方的社区SDK,可能会有十多个选项。

这次我尝试使用Go语言向NCMB发送请求。问题在于签名生成过程,通过将其作为函数进行封装,我们也可以考虑将其进行SDK化。

需要的库

本次使用的库如下:

import (
	"fmt"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"net/url"
	"sort"
	"time"
	"encoding/json"
	"github.com/go-resty/resty/v2"
	"github.com/tidwall/gjson"
)

定数的定义

这是一个基础常数,可用于……

// 定数の定義
const (
	ApplicationKey     = "YOUR_APPLICATION_KEY"
	SignatureMethod    = "HmacSHA256"
	SignatureVersion   = "2"
	FQDN               = "mbaas.api.nifcloud.com"
	ClientKey          = "YOUR_CLIENT_KEY"
)

主函数的流程

以下是main函数的代码。虽然本次中的objectId和definePath是空的,但可以在通用的签名生成中使用。

func main() {
	t := time.Now()
	where := map[string]string{
		"testKey": "testValue",
	}
	bytes, _ := json.Marshal(where)
	query := map[string]string{
		"where": string(bytes),
	}
	objectId := ""
	definePath := ""
	path := getPath("TestClass", objectId, definePath)
	signature, _ := createSignature("GET", "TestClass", t, query, objectId, definePath)

	// URLを作成
	partofUrl := &url.URL{
		Scheme: "https",
		Host: FQDN,
		Path: path,
		RawQuery: mapToQuery(query),
	}

	// Restyクライアントの生成
	client := resty.New()
	// リクエストの作成と送信
	resp, err := client.R().
      SetHeader("Content-Type", "application/json").
			SetHeader("X-NCMB-Application-Key", ApplicationKey).
			SetHeader("X-NCMB-Signature", signature).
			SetHeader("X-NCMB-Timestamp", t.Format("2006-01-02T15:04:05.999Z0700")).
      Get(partofUrl.String())
	if err != nil {
		fmt.Println(err)
	}
	// レスポンスの解析
	value := gjson.Get(resp.String(), "results")
	fmt.Println(value)
}

生成署名的函数。

以下是 createSignature 的内容。有关处理内容,请参考 REST API 参考:生成签名的方法 | 参考 Nifcloud 移动后端。

// 署名を作成する関数
func createSignature(method, className string, time time.Time, queries map[string]string, objectId string, definePath string) (string, error) {
	// パスの取得
	var path = getPath(className, objectId, definePath)
	// baseInfoの定義
	baseInfoMap := map[string]string{
		"X-NCMB-Application-Key": ApplicationKey,
		"SignatureMethod":        SignatureMethod,
		"SignatureVersion":       SignatureVersion,
		"X-NCMB-Timestamp":       time.Format("2006-01-02T15:04:05.999Z0700"),
	}

	// クエリが存在する場合は、それをbaseInfoMapに追加
	if queries != nil {
		for k, v := range queries {
			baseInfoMap[k] = url.QueryEscape(v)
		}
	}

	// 自然順序でソート
	var keys []string
	for k := range baseInfoMap {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	// baseInfoの作成
	var baseInfo string
	for _, k := range keys {
		if baseInfo != "" {
			baseInfo += "&"
		}
		baseInfo += k + "=" + baseInfoMap[k]
	}

	// 署名文字列の作成
	signatureString := method + "\n" + FQDN + "\n" + path + "\n" + baseInfo
	// HMACエンコーディング
	h := hmac.New(sha256.New, []byte(ClientKey))
	h.Write([]byte(signatureString))

	// Base64エンコーディング
	return base64.StdEncoding.EncodeToString(h.Sum(nil)), nil
}

其他

另外,还有一些准备好的函数。

// パスを取得する関数
func getPath(className string, objectId string, definePath string) string {
	if definePath != "" {
		return definePath
	} else if objectId != "" {
		return fmt.Sprintf("/2013-09-01/classes/%s/%s", className, objectId)
	} else {
		return fmt.Sprintf("/2013-09-01/classes/%s", className)
	}
}

// map型のクエリをstring型に変換する関数
func mapToQuery(queries map[string]string) string {
	var query string
	for k, v := range queries {
		if query != "" {
			query += "&"
		}
		query += k + "=" + url.QueryEscape(v)
	}
	return query
}

整个代码

可以利用此流程来搜索NCMB的数据存储。虽然不支持数据投稿,但只要将GET改为POST即可实现。

package main

import (
	"fmt"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"net/url"
	"sort"
	"time"
	"encoding/json"
	"github.com/go-resty/resty/v2"
	"github.com/tidwall/gjson"
)

// 定数の定義
const (
	ApplicationKey     = "YOUR_APPLICATION_KEY"
	SignatureMethod    = "HmacSHA256"
	SignatureVersion   = "2"
	FQDN               = "mbaas.api.nifcloud.com"
	ClientKey          = "YOUR_CLIENT_KEY"
)

// パスを取得する関数
func getPath(className string, objectId string, definePath string) string {
	if definePath != "" {
		return definePath
	} else if objectId != "" {
		return fmt.Sprintf("/2013-09-01/classes/%s/%s", className, objectId)
	} else {
		return fmt.Sprintf("/2013-09-01/classes/%s", className)
	}
}

// map型のクエリをstring型に変換する関数
func mapToQuery(queries map[string]string) string {
	var query string
	for k, v := range queries {
		if query != "" {
			query += "&"
		}
		query += k + "=" + url.QueryEscape(v)
	}
	return query
}

// 署名を作成する関数
func createSignature(method, className string, time time.Time, queries map[string]string, objectId string, definePath string) (string, error) {
	// パスの取得
	var path = getPath(className, objectId, definePath)
	// baseInfoの定義
	baseInfoMap := map[string]string{
		"X-NCMB-Application-Key": ApplicationKey,
		"SignatureMethod":        SignatureMethod,
		"SignatureVersion":       SignatureVersion,
		"X-NCMB-Timestamp":       time.Format("2006-01-02T15:04:05.999Z0700"),
	}

	// クエリが存在する場合は、それをbaseInfoMapに追加
	if queries != nil {
		for k, v := range queries {
			baseInfoMap[k] = url.QueryEscape(v)
		}
	}

	// 自然順序でソート
	var keys []string
	for k := range baseInfoMap {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	// baseInfoの作成
	var baseInfo string
	for _, k := range keys {
		if baseInfo != "" {
			baseInfo += "&"
		}
		baseInfo += k + "=" + baseInfoMap[k]
	}

	// 署名文字列の作成
	signatureString := method + "\n" + FQDN + "\n" + path + "\n" + baseInfo
	// HMACエンコーディング
	h := hmac.New(sha256.New, []byte(ClientKey))
	h.Write([]byte(signatureString))

	// Base64エンコーディング
	return base64.StdEncoding.EncodeToString(h.Sum(nil)), nil
}

func main() {
	t := time.Now()
	where := map[string]string{
		"testKey": "testValue",
	}
	bytes, _ := json.Marshal(where)
	query := map[string]string{
		"where": string(bytes),
	}
	objectId := ""
	definePath := ""
	path := getPath("TestClass", objectId, definePath)
	signature, _ := createSignature("GET", "TestClass", t, query, objectId, definePath)

	// URLの一部を作成
	partofUrl := &url.URL{
		Scheme: "https",
		Host: FQDN,
		Path: path,
		RawQuery: mapToQuery(query),
	}

	// Restyクライアントの生成
	client := resty.New()
	// リクエストの作成と送信
	resp, err := client.R().
      SetHeader("Content-Type", "application/json").
			SetHeader("X-NCMB-Application-Key", ApplicationKey).
			SetHeader("X-NCMB-Signature", signature).
			SetHeader("X-NCMB-Timestamp", t.Format("2006-01-02T15:04:05.999Z0700")).
      Get(partofUrl.String())
	if err != nil {
		fmt.Println(err)
	}
	// レスポンスの解析
	value := gjson.Get(resp.String(), "results")
	fmt.Println(value)
}

总结

Go语言被广泛应用于Web服务和命令行界面等领域。如果与NCMB集成,可以将其作为保存和获取数据的地方。

请把下面的句子用中文进行同意重述,只需要给出一种选择:

虽然在函数级别上,但请将NCMB与Go语言结合使用时,作为参考。

使用mBaaS,无需进行服务器开发!| NIFCLOUD移动后端

bannerAds