我想做的事:
我想向此 url 发送多个 get 请求:
https://catalog.wb.ru/brands/m/catalog?page=1&limit=300&brand=5786&dest=-1257786&sort=pricedown
然后收集“产品”对象内的所有数据。键“page”的值会自动递增以获取所有页面的数据。
实际上,我不太确定是否真的需要编写一个 json 来将其发送到前端。也许当我在 for 循环中收到新响应时发送不同的请求会更好?
我做了什么:
制作了正确的结构。通过单个请求,一切正常。
创建了 requestbodybytes []byte
和 productsbytes []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
}