Golang从API服务器获取数据的方法与实践

Golang从API服务器获取数据的方法与实践 我正在尝试理解Web API的相关知识。因此,我创建了一个简单的API,并通过客户端调用它。这非常基础,我完全不清楚自己在做什么。

客户端代码

package main

import (
	"fmt"
	"net/http"
)

func main() {
	reply, _ := http.Get("http://127.0.0.1:5051/test")
	reply.Body.Close()
	fmt.Println(reply.Body)
}

服务器端代码

package main

import (
	"net/http"
)

func main() {
	http.HandleFunc("/", get)
	http.ListenAndServe(":5051", nil)
}

func get(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Hello World"))
}

客户端得到的结果是这样的,而不是“Hello World”。

&{0xc0001c62c0 {0 0} true 0x1234aa0 0x1234a30}

我该如何将其转换为字符串?也欢迎提供任何其他建议或相关链接。


更多关于Golang从API服务器获取数据的方法与实践的实战教程也可以访问 https://www.itying.com/category-94-b0.html

9 回复

Body 是一个读取器,你需要从中读取实际的正文内容。

更多关于Golang从API服务器获取数据的方法与实践的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Client 允许您使用更高级的功能,如连接池,但从 GetPost 开始使用也是可以的。

是的,你可以直接使用 io.Reader 方法来避免为整个响应体分配潜在的大内存。

func main() {
    fmt.Println("hello world")
}

io.Reader 是一个接口。它的实现者提供了一个 Read() 方法,该方法接收一个输出缓冲区,并返回读取到缓冲区中的字节数以及一个错误。

func main() {
    fmt.Println("hello world")
}

我想我找到了一个解决方案:

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
)

func main() {
	reply, _ := http.Get("http://127.0.0.1:5051/test")
	defer reply.Body.Close()

	data, _ := ioutil.ReadAll(reply.Body)
	response := string(data)

	fmt.Println(response)
}

有没有其他方法可以实现?

你可以直接使用 io.Reader 方法

我该如何实现这个?

package main

import (
	"fmt"
	"io"
	"net/http"
)

func main() {
	reply, _ := http.Get("http://127.0.0.1:5051/test")
	defer reply.Body.Close()
	response := io.Reader(reply.Body)
	fmt.Println(response)
}

结果几乎相同:

&{0xc000076040 {0 0} false 0x1234aa0 0x1234a30}

Sibert:

http.Get

我来谈谈请求。

不要发送太多服务器请求!这会加重服务器端的负载!风险自负…

你可以使用 https//golang.org/pkg/net/http/#Client 发送稍微详细一些的请求。

从这里开始往下的内容我从未使用过。抱歉

  • type Dial 等等…

如果你精通 Go 语言,可能会想尝试 net 包。(我从未用过。😅) net package - net - Go Packages

  • 有建议使用 cgo 来使用 C 语言请求

这需要具备 C 语言知识。(我从未用过。😅) 以下链接是日文的,看起来你可以通过以下链接实现(我从未做过)* https://tomosoft.jp/design/?p=3636

我很高兴能提供一些帮助。

不要发送太多服务器请求!这会加重服务器端的负载!

我已经用客户端测试过了。使用这个(http.Client)而不是 http.Get 有什么好处?

客户端

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
)

func main() {
	http.HandleFunc("/", endpoint)
	err := http.ListenAndServe(":5050", nil)
	if err != nil {
		fmt.Println(err)
	}
}

func endpoint(w http.ResponseWriter, r *http.Request) {
	path := strings.Trim(r.URL.Path, "/")
	client := &http.Client{}
	url := ("http://94.237.92.101:6061/" + path)
	req, _ := http.NewRequest(http.MethodGet, url, nil)
	res, _ := client.Do(req)
	if res.Body != nil {
		defer res.Body.Close()
	}
	body, _ := ioutil.ReadAll(res.Body)
	w.Write(body)
}

具有2个端点的服务器

package main

import (
	"net/http"
	"strings"
)

func main() {
	http.HandleFunc("/", get)
	http.ListenAndServe(":6061", nil)
}

func get(w http.ResponseWriter, r *http.Request) {
	path := strings.Trim(r.URL.Path, "/")
	switch path {
	case "usrs":
		w.Write([]byte("user list"))
	case "posts":
		w.Write([]byte("post list"))
	default:
		w.Write([]byte("Unknown"))
	}
}

http://94.237.92.101:6061 http://94.237.92.101:6061/usrs http://94.237.92.101:6061/posts

在Go中,http.Response.Body是一个io.ReadCloser接口,需要读取其内容才能获取字符串数据。以下是修正后的客户端代码:

package main

import (
	"fmt"
	"io"
	"net/http"
)

func main() {
	// 发送GET请求
	reply, err := http.Get("http://127.0.0.1:5051/test")
	if err != nil {
		fmt.Printf("请求失败: %v\n", err)
		return
	}
	defer reply.Body.Close() // 确保关闭响应体

	// 读取响应体
	body, err := io.ReadAll(reply.Body)
	if err != nil {
		fmt.Printf("读取响应失败: %v\n", err)
		return
	}

	// 转换为字符串并打印
	fmt.Println(string(body))
}

更完整的实践示例,包含错误处理和状态码检查:

package main

import (
	"fmt"
	"io"
	"net/http"
)

func main() {
	client := &http.Client{}
	req, err := http.NewRequest("GET", "http://127.0.0.1:5051/test", nil)
	if err != nil {
		fmt.Printf("创建请求失败: %v\n", err)
		return
	}

	// 设置请求头
	req.Header.Set("User-Agent", "Go-API-Client/1.0")
	req.Header.Set("Accept", "application/json")

	// 发送请求
	resp, err := client.Do(req)
	if err != nil {
		fmt.Printf("发送请求失败: %v\n", err)
		return
	}
	defer resp.Body.Close()

	// 检查HTTP状态码
	if resp.StatusCode != http.StatusOK {
		fmt.Printf("服务器返回错误状态码: %d\n", resp.StatusCode)
		return
	}

	// 读取响应体
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("读取响应失败: %v\n", err)
		return
	}

	fmt.Printf("响应状态: %s\n", resp.Status)
	fmt.Printf("响应内容: %s\n", string(body))
}

处理JSON响应的示例:

package main

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
)

type APIResponse struct {
	Message string `json:"message"`
	Status  string `json:"status"`
}

func main() {
	resp, err := http.Get("http://127.0.0.1:5051/api/data")
	if err != nil {
		fmt.Printf("请求失败: %v\n", err)
		return
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("读取响应失败: %v\n", err)
		return
	}

	// 解析JSON响应
	var result APIResponse
	err = json.Unmarshal(body, &result)
	if err != nil {
		fmt.Printf("解析JSON失败: %v\n", err)
		return
	}

	fmt.Printf("消息: %s\n", result.Message)
	fmt.Printf("状态: %s\n", result.Status)
}

使用http.Get的简化版本:

package main

import (
	"fmt"
	"io"
	"net/http"
)

func main() {
	resp, err := http.Get("http://127.0.0.1:5051/test")
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	fmt.Println(string(body))
}

关键点:

  1. reply.Body需要调用io.ReadAll()读取字节数据
  2. 使用defer reply.Body.Close()确保资源释放
  3. 使用string(body)将字节切片转换为字符串
  4. 始终检查HTTP错误和状态码
回到顶部