卓越飞翔博客卓越飞翔博客

卓越飞翔 - 您值得收藏的技术分享站
技术文章34307本站已运行393

我有几个结构相同的 JSON。他们的对象是对象数组。如何将这些数组附加到一个数组中?

我有几个结构相同的 json。他们的对象是对象数组。如何将这些数组附加到一个数组中?

问题内容

我想做的事:

我想向此 url 发送多个 get 请求: https://catalog.wb.ru/brands/m/catalog?page=1&limit=300&brand=5786&dest=-1257786&sort=pricedown 然后收集“产品”对象内的所有数据。键“p​​age”的值会自动递增以获取所有页面的数据。

实际上,我不太确定是否真的需要编写一个 json 来将其发送到前端。也许当我在 for 循环中收到新响应时发送不同的请求会更好?

我做了什么:

制作了正确的结构。通过单个请求,一切正常。

创建了 requestbodybytes []byteproductsbytes []byte,以便将它们与 ioutil.readall 中的 []bytes 一起附加。 打印 requestbodybytes 的长度我发现它随着每个请求而扩展,但是在我解组它之后,我在输出中看到空结构。

我知道发生这种情况是因为每个请求我都会收到 type response 的新 json。但是,如果我需要由 type response 的多个 json 中的“产品”对象组成的 product structs 切片,该怎么办?

注意:需要在 for 循环内初始化 requestbodybytes 以使用它来停止发送请求,因为当页面上没有信息时,服务器会给出 200 代码和空 json。

提前谢谢您!

const URL = "https://catalog.wb.ru/brands/m/catalog?page=%d&limit=300&brand=5786&dest=-1257786&sort=pricedown"

type Response struct {
    Data struct {
        Products []Product `json:"products"`
    } `json:"data"`
}

type Product struct {
    ID     int     `json:"id"`
    Name   string  `json:"name"`
    Price  int     `json:"priceU"`
    Rating float32 `json:"reviewRating"`
    Sale   int     `json:"sale"`
    New    bool    `json:"isNew"`
}

func main() {
    var response Response
    var products Response //Also tried to make it []Response
    var ProductsBytes []byte

    for i := 1; ; i++ {
        resp, err := http.Get(fmt.Sprintf(URL, i))
        if err != nil {
            fmt.Printf("#1 Error: %s", err)
        }
        defer resp.Body.Close()

        bytes, err := ioutil.ReadAll(resp.Body)
        var requestBodyBytes []byte
        requestBodyBytes = append(requestBodyBytes, bytes...)
        ProductsBytes = append(ProductsBytes, bytes...)

        json.Unmarshal(requestBodyBytes, &response)

        fmt.Println(resp.Status)
        fmt.Printf("nSlice from page #%dnLength of bytes: %dn", i, len(bytes))
        fmt.Printf("Length of finalResult: %dn", len(requestBodyBytes))
        if len(response.Data.Products) == 0 {
            fmt.Println("There's no more data")
            break
        }
    }

    json.Unmarshal(ProductsBytes, &products)

    fmt.Println(response)
    fmt.Println(products)
    fmt.Println(len(products))
}


正确答案


没有理由收集所有原始响应字节。只需单独解组每个响应并将每个页面的产品附加到包含所有产品的某个切片即可。另外,在循环中调用 defer resp.body.close() 可能不是您想要的。延迟语句仅在循环结束后执行,因此连接不能重新用于请求。将循环体提取到它自己的函数中使这变得更加清晰:

package main

import (
    "encoding/json"
    "errors"
    "fmt"
    "log"
    "net/http"
)

const URL = "https://catalog.wb.ru/brands/m/catalog?page=%d&limit=300&brand=5786&dest=-1257786&sort=pricedown"

type Response struct {
    Data struct {
        Products []Product `json:"products"`
    } `json:"data"`
}

type Product struct {
    ID     int     `json:"id"`
    Name   string  `json:"name"`
    Price  int     `json:"priceU"`
    Rating float32 `json:"reviewRating"`
    Sale   int     `json:"sale"`
    New    bool    `json:"isNew"`
}

func main() {
    var allProducts []Product

    for i := 1; ; i++ {
        page, err := fetchPage(i)
        if err != nil {
            log.Fatal(err) // TODO
        }

        allProducts = append(allProducts, page...)

        if len(page) == 0 {
            break
        }
    }

    fmt.Println(allProducts)
    fmt.Println(len(allProducts))
}

func fetchPage(i int) ([]Product, error) {
    resp, err := http.Get(fmt.Sprintf(URL, i))
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    if resp.StatusCode != 200 {
        return nil, errors.New(resp.Status)
    }

    var response Response
    err = json.NewDecoder(resp.Body).Decode(&response)
    if err != nil {
        return nil, err
    }

    return response.Data.Products, nil
}
上一篇: 如何在 golang 中使用 kubernetes 服务帐户?
下一篇: 返回列表
留言与评论(共有 0 条评论)
   
验证码:
隐藏边栏