Golang中使用HTTP请求获取词典信息 | 青训营
在这篇教程中,我们将学习如何使用Go语言(Golang)编写一个简单的程序,通过发送HTTP请求来获取词典信息。我们将使用net/http包来处理HTTP请求,以及encoding/json包来解析JSON响应。
1. 简介
本教程中的代码示例展示了如何通过发送HTTP POST请求来查询一个英文单词的词典信息。我们将使用彩云小译的API来获取词典数据。
2. 导入所需的包
首先,我们需要导入所需的包,包括net/http用于发送HTTP请求,以及encoding/json用于处理JSON数据。
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
)
3. 定义请求和响应结构体
我们需要定义用于请求和响应的结构体,以便于编码和解析JSON数据。
type DictRequest struct {
TransType string `json:"trans_type"`
Source string `json:"source"`
}
type DictResponse struct {
Rc int `json:"rc"`
Wiki struct {
} `json:"wiki"`
Dictionary struct {
Prons struct {
EnUs string `json:"en-us"`
En string `json:"en"`
} `json:"prons"`
Explanations []string `json:"explanations"`
// ... 其他字段 ...
} `json:"dictionary"`
}
4. 编写查询函数
我们编写一个名为query的函数,用于发送HTTP请求并解析响应数据。
func query(word string) {
client := &http.Client{}
request := DictRequest{TransType: "en2zh", Source: word}
buf, err := json.Marshal(request)
if err != nil {
log.Fatal(err)
}
var data = bytes.NewReader(buf)
req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
// ... 设置请求头 ...
resp, err := client.Do(req)
// ... 处理响应 ...
// 解析JSON响应
var dictResponse DictResponse
err = json.Unmarshal(bodyText, &dictResponse)
// ... 处理解析后的数据 ...
}
当解析函数 query(word string) 被调用时,它会执行以下步骤:
- 创建 HTTP 客户端:
client := &http.Client{}
这里我们创建了一个 HTTP 客户端,用于发送 HTTP 请求。
- 构建请求体:
request := DictRequest{TransType: "en2zh", Source: word}
buf, err := json.Marshal(request)
if err != nil {
log.Fatal(err)
}
var data = bytes.NewReader(buf)
在这里,我们构建了一个包含了要查询的单词信息的 JSON 请求体。然后使用 json.Marshal 函数将请求结构体序列化为 JSON 格式的字节流。如果序列化过程中出现错误,程序将使用 log.Fatal 函数打印错误并终止。
- 创建并发送 HTTP 请求:
req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
// ... 设置请求头 ...
resp, err := client.Do(req)
在这里,我们创建了一个 HTTP POST 请求,将之前构建的请求体放入请求中。然后使用 client.Do(req) 发送请求,并得到响应。
- 处理响应:
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
bodyText, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
在这里,我们首先检查响应是否有错误。如果有错误,我们使用 log.Fatal 打印错误信息并终止程序。然后,我们读取响应体的内容,并确保在函数结束时关闭响应体。
- 解析 JSON 响应:
var dictResponse DictResponse
err = json.Unmarshal(bodyText, &dictResponse)
在这里,我们使用 json.Unmarshal 函数将响应体的 JSON 数据解析到 dictResponse 结构体中。这里假设 bodyText 是包含 JSON 数据的字节流。如果解析过程中出现错误,程序将使用 log.Fatal 打印错误并终止。
- 处理解析后的数据:
fmt.Println(word, "UK", dictResponse.Dictionary.Prons.En, "US", dictResponse.Dictionary.Prons.EnUs)
for _, item := range dictResponse.Dictionary.Explanations {
fmt.Println(item)
}
在这里,我们从 dictResponse 结构体中提取了一些信息并进行了打印。具体来说,我们打印了查询的单词、英式和美式发音,以及词义解释列表。
总之,这个解析函数执行了从构建请求到处理响应再到解析 JSON 数据的整个流程。这使得我们可以从外部 API 获取词典信息并将其解析为易于理解的格式。这是一个典型的 HTTP 请求和 JSON 解析的应用场景,你可以根据这个示例来构建更复杂的应用程序。
5. 处理HTTP响应
在query函数中,我们发送HTTP请求并接收响应。我们需要处理响应状态码和响应体数据。
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
bodyText, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
if resp.StatusCode != 200 {
log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))
}
- 发送请求并获取响应:
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
这里我们使用 client.Do(req) 来发送之前构建的HTTP请求 req,并获得一个响应对象 resp。同时,我们检查是否有发送请求时的错误,如果有错误,使用 log.Fatal 输出错误信息并终止程序。
- 延迟关闭响应体:
defer resp.Body.Close()
在函数返回之前,我们使用 defer 关键字来确保响应体在所有处理完成后关闭。这个步骤很重要,以防止资源泄漏。
- 读取响应体的内容:
bodyText, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
这里使用 io.ReadAll(resp.Body) 来读取响应体的全部内容,并将其存储在 bodyText 变量中。如果读取过程中发生错误,程序将使用 log.Fatal 打印错误并终止。
- 检查响应状态码:
if resp.StatusCode != 200 {
log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))
}
在这一步中,我们检查响应的状态码是否为200。一般来说,HTTP状态码200表示成功的响应。如果状态码不是200,说明可能出现了错误,我们使用 log.Fatal 打印错误消息,包括状态码和响应体的内容,并终止程序。
6. 解析JSON数据
我们使用json.Unmarshal函数来解析JSON响应数据,然后从解析后的数据中提取所需的信息。
var dictResponse DictResponse
err = json.Unmarshal(bodyText, &dictResponse)
if err != nil {
log.Fatal(err)
}
fmt.Println(word, "UK", dictResponse.Dictionary.Prons.En, "US", dictResponse.Dictionary.Prons.EnUs)
for _, item := range dictResponse.Dictionary.Explanations {
fmt.Println(item)
}
在这部分代码中,我们从响应体中解析JSON数据,并从解析后的数据中提取所需的信息。
- 解析JSON数据:
var dictResponse DictResponse
err = json.Unmarshal(bodyText, &dictResponse)
if err != nil {
log.Fatal(err)
}
使用 json.Unmarshal 函数将响应体中的JSON数据解析到 dictResponse 变量中。我们传递了 bodyText,即响应体的内容,作为要解析的数据,同时也传递了指向 dictResponse 的指针,以便将解析结果填充到该结构体中。如果解析过程中发生错误,使用 log.Fatal 打印错误信息并终止程序。
- 提取并打印信息:
fmt.Println(word, "UK", dictResponse.Dictionary.Prons.En, "US", dictResponse.Dictionary.Prons.EnUs)
for _, item := range dictResponse.Dictionary.Explanations {
fmt.Println(item)
}
这部分代码使用解析后的数据 dictResponse 来提取所需的信息并打印出来。具体来说:
dictResponse.Dictionary.Prons.En和dictResponse.Dictionary.Prons.EnUs分别表示英式发音和美式发音,我们使用fmt.Println打印这两个发音信息。- 使用
for循环遍历dictResponse.Dictionary.Explanations切片,该切片包含了单词的解释,然后逐行打印出每个解释。
通过以上代码,我们实现了从解析后的JSON数据中提取词典信息并进行打印输出。这一部分是整个程序的核心,它将收集的数据以易读的方式呈现给用户,使用户可以查看单词的发音和解释等信息。
7.请求头设置
在发送HTTP请求时,我们设置了一系列的请求头。这些请求头是为了模拟浏览器的请求,确保请求能够正确发送并得到响应。在实际应用中,你可能需要根据实际情况调整这些请求头。具体的生成过程点击这里。
req.Header.Set("authority", "api.interpreter.caiyunai.com")
req.Header.Set("accept", "application/json, text/plain, */*")
req.Header.Set("accept-language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6")
req.Header.Set("app-name", "xy")
req.Header.Set("content-type", "application/json;charset=UTF-8")
req.Header.Set("device-id", "307998dce7d27d2fae6106d2d2d6befc")
req.Header.Set("origin", "https://fanyi.caiyunapp.com")
req.Header.Set("os-type", "web")
req.Header.Set("os-version", "")
req.Header.Set("referer", "https://fanyi.caiyunapp.com/")
req.Header.Set("sec-ch-ua", `"Not/A)Brand";v="99", "Microsoft Edge";v="115", "Chromium";v="115"`)
req.Header.Set("sec-ch-ua-mobile", "?0")
req.Header.Set("sec-ch-ua-platform", `"Windows"`)
req.Header.Set("sec-fetch-dest", "empty")
req.Header.Set("sec-fetch-mode", "cors")
req.Header.Set("sec-fetch-site", "cross-site")
req.Header.Set("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.188")
req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi")
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
8. 主函数
func main() {
if len(os.Args) != 2 {
fmt.Fprintf(os.Stderr, `usage: simpleDict WORD example: simpleDict hello`)
os.Exit(1)
}
word := os.Args[1]
query(word)
}
9. 全部代码
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
//"strings"
)
type DictRequest struct {
TransType string `json:"trans_type"`
Source string `json:"source"`
}
type DictResponse struct {
Rc int `json:"rc"`
Wiki struct {
} `json:"wiki"`
Dictionary struct {
Prons struct {
EnUs string `json:"en-us"`
En string `json:"en"`
} `json:"prons"`
Explanations []string `json:"explanations"`
Synonym []string `json:"synonym"`
Antonym []string `json:"antonym"`
WqxExample [][]string `json:"wqx_example"`
Entry string `json:"entry"`
Type string `json:"type"`
Related []interface{} `json:"related"`
Source string `json:"source"`
} `json:"dictionary"`
}
func query(word string) {
client := &http.Client{}
//var data = strings.NewReader(`{"trans_type":"en2zh","source":"good"}`)
request := DictRequest{TransType: "en2zh", Source: word}
buf, err := json.Marshal(request)
if err != nil {
log.Fatal(err)
}
var data = bytes.NewReader(buf)
req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
if err != nil {
log.Fatal(err)
}
req.Header.Set("authority", "api.interpreter.caiyunai.com")
req.Header.Set("accept", "application/json, text/plain, */*")
req.Header.Set("accept-language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6")
req.Header.Set("app-name", "xy")
req.Header.Set("content-type", "application/json;charset=UTF-8")
req.Header.Set("device-id", "307998dce7d27d2fae6106d2d2d6befc")
req.Header.Set("origin", "https://fanyi.caiyunapp.com")
req.Header.Set("os-type", "web")
req.Header.Set("os-version", "")
req.Header.Set("referer", "https://fanyi.caiyunapp.com/")
req.Header.Set("sec-ch-ua", `"Not/A)Brand";v="99", "Microsoft Edge";v="115", "Chromium";v="115"`)
req.Header.Set("sec-ch-ua-mobile", "?0")
req.Header.Set("sec-ch-ua-platform", `"Windows"`)
req.Header.Set("sec-fetch-dest", "empty")
req.Header.Set("sec-fetch-mode", "cors")
req.Header.Set("sec-fetch-site", "cross-site")
req.Header.Set("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.188")
req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi")
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
bodyText, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
if resp.StatusCode != 200 {
log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))
}
//fmt.Printf("%s\n", bodyText)
var dictResponse DictResponse
err = json.Unmarshal(bodyText, &dictResponse)
if err != nil {
log.Fatal(err)
}
//fmt.Printf("%#v\n",dictResponse)
fmt.Println(word, "UK", dictResponse.Dictionary.Prons.En, "US", dictResponse.Dictionary.Prons.EnUs)
for _, item := range dictResponse.Dictionary.Explanations {
fmt.Println(item)
}
}
func main() {
if len(os.Args) != 2 {
fmt.Fprintf(os.Stderr, `usage: simpleDict WORD example: simpleDict hello`)
os.Exit(1)
}
word := os.Args[1]
query(word)
}
10. 总结
通过以上步骤,我们实现了一个简单的Golang程序,用于查询英文单词的词典信息。我们通过发送HTTP请求,解析JSON响应,并从中提取所需的信息。实现了一个简单的词典查询工具,能够通过调用彩云小译的 API 来获取英文单词的词义和发音等信息。合理地构建了 HTTP 请求、处理了请求和响应的数据,并进行了错误处理,使得工具在正常情况下能够稳定运行。通过这个例子,我们学习了如何使用 Go 语言进行网络请求、JSON 数据处理和命令行参数获取,为实际应用场景提供了一种实现方式。在现实世界中,类似的技术可以用于开发各种实用工具和应用程序。