iT邦幫忙

0

请问 go 怎么处理 json 数据

  • 分享至 

  • xImage

我正在写一段 go 通过 http api 或者 F5 的信息,并且可以获取到 json 数据,但我只想要制定的字段的值,当我通过 json.Unmarshal 解码 json 数据时却报错了。
错位信息:

.\license.go:49:6: no new variables on left side of :=

代码内容:

package main

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"time"
)

var (
	Username = "admin"
	Password = "123456"
)

type license struct {
	licenseStartDate string
	licenseEndDate   int
}

func call(url, method string) error {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{
		Transport: tr,
		Timeout:   time.Second * 10,
	}

	req, err := http.NewRequest(method, url, nil)
	if err != nil {
		return fmt.Errorf("Got error %s", err.Error())
	}
	req.SetBasicAuth(Username, Password)
	response, err := client.Do(req)
	if err != nil {
		return fmt.Errorf("Got error %s", err.Error())
	}
	defer response.Body.Close()
	body, _ := ioutil.ReadAll(response.Body)
	res := string(body)      // 这个时直接获取到的数据

	j := []byte(res)

	var l license
	
	err := json.Unmarshal(j, &l)       //报错位置

	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("licenseStartDate: %s\nlicenseEndDate: %s", l.licenseStartDate, l.licenseEndDate)

	return nil
}

func main() {
	call("https://<mg ip>/mgmt/tm/sys/license", "GET")
}

直接获取到的数据内容:

{"kind":"tm:sys:license:licensestats","selfLink":"https://localhost/mgmt/tm/sys/license?ver=16.1.2.1","entries":{"https://localhost/mgmt/tm/sys/license/0":{"nestedStats":{"entries":{"dailyRenewNotifPeriod":{"description":"5"},"licenseEndDate":{"description":"2023/05/12"},"licenseStartDate":{"description":"2023/04/10"},"licensedOnDate":{"description":"2023/04/11"},"licensedVersion":{"description":"16.1.2"},"platformId":{"description":"Z100"},"registrationKey":{"description":"XXXXXXXXXXXXXXXXXXXXXXXXXXX"},"serviceCheckDate":{"description":"2023/04/10"},"https://localhost/mgmt/tm/sys/license/0/active-modules":{"nestedStats":{"entries":{"https://localhost/mgmt/tm/sys/license/0/active-modules/%22BIG-IP,%20VE%20Trial%22":{"nestedStats":{"entries":{"featureModules":{"description":"{ \"Rate Shaping\" \"External Interface and Network HSM, VE\" \"SDN Services, VE\" \"SSL, Forward Proxy, VE\" \"BIG-IP VE, Multicast Routing\" \"APM, Limited\" \"SSL, VE\" \"DNS (1K QPS), VE\" \"Routing Bundle, VE\" \"ASM, VE\" \"Crytpo Offload, VE, Tier 1 (25M - 200M)\" \"Max Compression, VE\" \"AFM, VE\" \"Advanced Web Application Firewall, VE\" \"DNSSEC\" \"Anti-Virus Checks\" \"Base Endpoint Security Checks\" \"Firewall Checks\" \"Network Access\" \"Secure Virtual Keyboard\" \"APM, Web Application\" \"Machine Certificate Checks\" \"Protected Workspace\" \"Remote Desktop\" \"App Tunnel\" \"VE, Carrier Grade NAT (AFM ONLY)\" \"PSM, VE\" }"},"key":{"description":"SDGNLAO-EGDMHQK"}}}}}}}}}}}}
從您提供的代碼和數據看,您的代碼中 license 結構體的 licenseEndDate 字段定義為 int 類型,但是實際數據中該字段是一個字符串類型,這是導致 json.Unmarshal 函數報錯的原因之一。

您可以將 licenseEndDate 字段定義為 string 類型,然後在代碼中將其轉換為需要的格式。例如,您可以使用 time.Parse 函數將日期字符串轉換為 time.Time 類型,然後在需要的地方使用 time.Time 類型。另外,如果您只需要解析 JSON 數據中的指定字段,可以使用 json.RawMessage 類型來表示未知的 JSON 數據。

下面是修改過的代碼示例:

package main

import (
"crypto/tls"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"time"
)

var (
Username = "admin"
Password = "123456"
)

type license struct {
LicenseStartDate string `json:"licenseStartDate"`
LicenseEndDate string `json:"licenseEndDate"`
}

func call(url, method string) error {
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{
Transport: tr,
Timeout: time.Second * 10,
}

req, err := http.NewRequest(method, url, nil)
if err != nil {
return fmt.Errorf("Got error %s", err.Error())
}
req.SetBasicAuth(Username, Password)
response, err := client.Do(req)
if err != nil {
return fmt.Errorf("Got error %s", err.Error())
}
defer response.Body.Close()
body, _ := ioutil.ReadAll(response.Body)

var res struct {
License license `json:"entries"`
}
err = json.Unmarshal(body, &res)
if err != nil {
return fmt.Errorf("Got error %s", err.Error())
}

licenseStartDate, err := time.Parse("2006/01/02", res.License.LicenseStartDate)
if err != nil {
return fmt.Errorf("Got error %s", err.Error())
}
fmt.Printf("licenseStartDate: %s\n", licenseStartDate.Format("2006/01/02"))

licenseEndDate, err := time.Parse("2006/01/02", res.License.LicenseEndDate)
if err != nil {
return fmt.Errorf("Got error %s", err.Error())
}
fmt.Printf("licenseEndDate: %s\n", licenseEndDate.Format("2006/01/02"))

return nil
}

func main() {
call("https://<mg ip>/mgmt/tm/sys/license", "GET")
}


這個示例將 licenseEndDate 字段定義為 string 類型,並使用 time.Parse 函數將日期字符串轉換為 time.Time 類型。注意,time.Parse 函數的第一個參數是時間格式,可以根據您的實際情況進行修改。

此外,將 JSON 數據解析為指定結構體時,建議使用與結構體字段匹配的標記,例如上面示例中的 json:"licenseStartDate" 和 json:"licenseEndDate"。這可以確保 JSON 數據中的字段正確地解析為相應的結構體字段。
obarisk iT邦研究生 1 級 ‧ 2023-04-21 08:41:15 檢舉
只要某些欄位,可以考慮用只查詢的套件,比如

https://github.com/antchfx/jsonquery
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 個回答

0
whitefloor
iT邦研究生 2 級 ‧ 2023-04-20 12:52:05
最佳解答

你沒看console跳給你的錯誤訊息
也沒看Funciton註記跟回傳值
也沒看Package使用方法

  1. .\license.go:49:6: no new variables on left side of :=
    你前面已經透過
    req, err := http.NewRequest(method, url, nil)
    宣告了err,所以在這段function內要用到err直接用=再次賦值就好
    但是要注意後面再次賦值給err會蓋過前面的value

    這段跟你json有問題的部分完全沒關係
    最好去用個IDE開發,這個還不用編譯在static check的時候就會報錯了

  2. body, _ := ioutil.ReadAll(response.Body)
    這段Package API的回傳值本身就是[]byte,所以下面在string跟byte互轉完全沒必要

  3. 去看一下 struct tag語法使用跟json package使用方法,json package在encoding/decoding的時候會有影響

  4. json package在unexport struct field是無法使用的

  5. fmt.Printf("licenseStartDate: %s\nlicenseEndDate: %s", l.licenseStartDate, l.licenseEndDate)
    這段也有跳警告出來,自己看一下怎麼修吧

網路範例參考
https://riptutorial.com/go/example/14194/marshaling-structs-with-private-fields

as900 iT邦研究生 4 級 ‧ 2023-04-20 13:41:18 檢舉

第 5 个是因为调试后,忘记改回去了

licenseEndDate   int  //这里应该是 string

我要發表回答

立即登入回答