如何在Go中解组通过http检索的JSON

huangapple go评论89阅读模式
英文:

How to Unmarshall JSON Retrived over http in Go

问题

我正在访问一个返回JSON的API,格式如下:

[{"UniqueID":1234, "DocID":5678}, {"UniqueID":5678, "DocID":9101112}]

这个API是用Go语言编写的,示例输出是在浏览器中显示的。content-type头部是application/json。

我有以下代码来获取和解析这个数据:

type UniqueIDDocID struct{
    UniqueID int64 `json: "UniqueID"`
    DocID int64 `json: "DocID"`
}
type UniqueIDDocIDCollection struct{
    FullList []UniqueIDDocID
}

func retrieveUniqueIDByPublication(nodeid int64, publication string){
    // 调用API
    //hgr := new(retrieval.HttpGetRetrieval)
    // endpoint在这里定义 - 我已经为了隐私原因删除了
    fmt.Println(endpoint) // 我知道这个URL是有效的
    /*response, err := hgr.RequestResponse(endpoint)
        if err != nil {
            l4g.Warn("无法获取端点%s。错误:", endpoint, err)
            return
        }
        defer hgr.CloseResponse(response)
        queryResult := hgr.ReadResponse(response)*/
        client := new(http.Client)
        request, err := http.NewRequest("GET", endpoint, nil)
        if err != nil {
            l4g.Warn("无法获取端点%s。错误:%v", endpoint, err)
            return    
        }
        request.Header.Set("Content-Type", "applicaiton/json")
        response, err := client.Do(request)
        if err != nil {
            l4g.Warn("无法获取端点%s。错误:%v", endpoint, err)
            return    
        }
        defer response.Body.Close()
        var reader io.ReadCloser
        reader = response.Body
        defer reader.Close()
        queryResult, readErr := ioutil.ReadAll(reader)
        if err != nil {
            l4g.Warn("无法获取端点%s。错误:%v", endpoint, readErr)
            return    
        }
        if queryResult == nil {
            l4g.Warn("没有返回%s。", endpoint)
            return
        }
        

        var details UniqueIDDocIDCollection
    // 处理返回结果
        if err:=json.Unmarshal(queryResult, &details); err != nil{
            l4g.Warn("无法从%s解析返回结果%v。错误:%s", endpoint, queryResult, err)
            return
        }
        writeUniqueIDFile(details)
}

我得到了"无法解析"的消息,日志中的详细信息显示如下:

[91 123 34 85 110 105 113 117 101 73 68 34 58 34 56 51     57 51 50 53 56 54 34 44 34 68 111 99 73 68 34 58 52 49 50 49 54 57 49 57 125 44 123 34 85 110 105 113 117 101]

作为一个代表性的示例。

在这个解析步骤中我做错了什么?

我希望的输出是UniqueIDDocIDCollection结构上有一个切片,其中包含类型为UniqueIDDocID的项,然后我可以从中获取UniqueID并将其写入一个以行分隔的文件。

我已经在Google上搜索了一些东西,并尝试了一些方法,但每次都是这样的结果。

如果你对源JSON有任何建议,请分享,因为我可能能够在API中进行更改。

提前感谢您的帮助
Nathan

英文:

I am accessing an API that returns JSON in the form:

[{"UniqueID":1234, "DocID":5678}, {"UniqueID":5678, "DocID":9101112}]

this API was written in Go and that sample output is how the return is displayed in a browser. the content-type header is application/json

I have the following code to retrieve and unmarshal this:

    type UniqueIDDocID struct{
    	UniqueID int64 `json: "UniqueID"`
    	DocID int64 `json: "DocID"`
    }
    type UniqueIDDocIDCollection struct{
    	FullList []UniqueIDDocID
    }
    
    func retrieveUniqueIDByPublication(nodeid int64, publication string){
    	// call the API
    	//hgr := new(retrieval.HttpGetRetrieval)
// endpoint is defined here - I have removed for privacy reasons
    	fmt.Println(endpoint) // the url which I know works
    	/*response, err := hgr.RequestResponse(endpoint)
    		if err != nil {
    			l4g.Warn("Could not retrieve the endpoint %s. Error: ", endpoint, err)
    			return
    		}
    		defer hgr.CloseResponse(response)
    		queryResult := hgr.ReadResponse(response)*/
    		client := new(http.Client)
    		request, err := http.NewRequest("GET", endpoint, nil)
    		if err != nil {
    			l4g.Warn("Could not retrieve the endpoint %s. Error: %v", endpoint, err)
    			return	
    		}
    		request.Header.Set("Content-Type", "applicaiton/json")
    		response, err := client.Do(request)
    		if err != nil {
    			l4g.Warn("Could not retrieve the endpoint %s. Error: %v", endpoint, err)
    			return	
    		}
    		defer response.Body.Close()
    		var reader io.ReadCloser
    		reader = response.Body
    		defer reader.Close()
    		queryResult, readErr := ioutil.ReadAll(reader)
    		if err != nil {
    			l4g.Warn("Could not retrieve the endpoint %s. Error: %v", endpoint, readErr)
    			return	
    		}
    		if queryResult == nil {
    			l4g.Warn("Nothing returned %s.", endpoint)
    			return
    		}
    		
    
    		var details UniqueIDDocIDCollection
    	// process return
    		if err:=json.Unmarshal(queryResult, &details); err != nil{
    			l4g.Warn("Failed to unmarshall return %v from %s", queryResult, endpoint)
    			return
    		}
    		writeUniqueIDFile(details)
    }

I am getting the "Failed to Unmarshall" message and the details in the log shows things like:

[91 123 34 85 110 105 113 117 101 73 68 34 58 34 56 51     57 51 50 53 56 54 34 44 34 68 111 99 73 68 34 58 52 49 50 49 54 57 49 57 125 44 123 34 85 110 105 113 117 101]

As a representative sample.

What am I doing wrong in this unmarshall step?

My desired output is that the UniqueIDDocIDCollection structu has a slice on it that contains items of type UniqueIDDocID that I can then take the UniqueID from and write it to a line delimited file.

I have been Googling around and have tried a number of things but each time this is what I get.

If you have any suggestions about the source JSON too then share those as I may be able to make the changes in the API.

Thanks for the help in advance
Nathan

答案1

得分: 1

错误数据是一个[]byte切片;如果你将其Printf为%s(fmt.Printf("foo: %s\n", foo))或者在现在的位置用string(foo)包装起来,你可能会得到更有用的东西。

我制作了一个更简单的Unmarshall示例,看起来工作得很好。我怀疑问题实际上是输入数据有问题?

package main

import (
	"encoding/json"
	"log"
)

type UniqueIDDocID struct {
	UniqueID int64 `json:"UniqueID"`
	DocID    int64 `json:"DocID"`
}
type UniqueIDDocIDCollection struct {
	FullList []UniqueIDDocID
}

const INPUT = `[{"UniqueID":1234, "DocID":5678}, {"UniqueID":5678, "DocID":9101112}]`

func main() {

	coll := new(UniqueIDDocIDCollection)

	err := json.Unmarshal([]byte(INPUT), &coll.FullList)

	if err != nil {
		log.Printf("Could not unmarshall %s: %s", INPUT, err)
	}

	log.Printf("Now have data: %#v\n", coll)

}

输出(在play.golang上试一试

Now have data: &main.UniqueIDDocIDCollection{FullList:[]main.UniqueIDDocID{main.UniqueIDDocID{UniqueID:1234, DocID:5678}, main.UniqueIDDocID{UniqueID:5678, DocID:9101112}}}

首先将错误消息中的%v更改为%s;也许你没有得到你期望的数据。你还应该包含json.Unmarshall返回的错误,它可能会告诉你出了什么问题。 如何在Go中解组通过http检索的JSON

英文:

The error data is a []byte slice; you will likely get something more useful if you Printf it to a %s (fmt.Printf("foo: %s\n", foo)) or wherever you have it now wrap it in string(foo).

I made a simpler example of your Unmarshall, and it seems to work fine. I suspect the problem is with the input data after all?

package main

import (
	"encoding/json"
	"log"
)

type UniqueIDDocID struct {
	UniqueID int64 `json: "UniqueID"`
	DocID    int64 `json: "DocID"`
}
type UniqueIDDocIDCollection struct {
	FullList []UniqueIDDocID
}

const INPUT = `[{"UniqueID":1234, "DocID":5678}, {"UniqueID":5678, "DocID":9101112}]`

func main() {

	coll := new(UniqueIDDocIDCollection)

	err := json.Unmarshal([]byte(INPUT), &coll.FullList)

	if err != nil {
		log.Printf("Could not unmarshall %s: %s", INPUT, err)
	}

	log.Printf("Now have data: %#v\n", coll)

}

Outputs (try it on play.golang)

Now have data: &main.UniqueIDDocIDCollection{FullList:[]main.UniqueIDDocID{main.UniqueIDDocID{UniqueID:1234, DocID:5678}, main.UniqueIDDocID{UniqueID:5678, DocID:9101112}}}

Start by changing %v to %s in the "failed to unmarshall" error message; maybe you don't have the data you are expecting. You should also include the error returned from json.Unmarshall, it might tell you what's going wrong. 如何在Go中解组通过http检索的JSON

huangapple
  • 本文由 发表于 2013年7月24日 00:05:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/17815364.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定