写在前面
本人准大二,之前也没有后端开发经验(本人主业是搞人工智能的),也没有学过计算机网络(408只学了数据结构),也没有go语言基础,语言只学过C++和Python。这篇文章完全是我现学现卖的,所以我会从初学者的视角讲讲这个项目,希望可以帮到和我一样的初学者。
解析正文
源代码:
jspackage
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
)
type DictRequest struct {
TransType string `json:"trans_type"`
Source string `json:"source"`
UserID string `json:"user_id"`
}
type DictResponse struct {
Rc int `json:"rc"`
Wiki struct {
KnownInLaguages int `json:"known_in_laguages"`
Description struct {
Source string `json:"source"`
Target interface{} `json:"target"`
} `json:"description"`
ID string `json:"id"`
Item struct {
Source string `json:"source"`
Target string `json:"target"`
} `json:"item"`
ImageURL string `json:"image_url"`
IsSubject string `json:"is_subject"`
Sitelink string `json:"sitelink"`
} `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{}
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("Connection", "keep-alive")
req.Header.Set("DNT", "1")
req.Header.Set("os-version", "")
req.Header.Set("sec-ch-ua-mobile", "?0")
req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36")
req.Header.Set("app-name", "xy")
req.Header.Set("Content-Type", "application/json;charset=UTF-8")
req.Header.Set("Accept", "application/json, text/plain, */*")
req.Header.Set("device-id", "")
req.Header.Set("os-type", "web")
req.Header.Set("X-Authorization", "token:qgemv4jr1y38jyq6vhvi")
req.Header.Set("Origin", "https://fanyi.caiyunapp.com")
req.Header.Set("Sec-Fetch-Site", "cross-site")
req.Header.Set("Sec-Fetch-Mode", "cors")
req.Header.Set("Sec-Fetch-Dest", "empty")
req.Header.Set("Referer", "https://fanyi.caiyunapp.com/")
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
req.Header.Set("Cookie", "_ym_uid=16456948721020430059; _ym_d=1645694872")
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
bodyText, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
if resp.StatusCode != 200 {
log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))
}
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)
}
}
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)
}
首先我认为,看代码之前,搞清楚整个宏观在干什么是很有必要的。所以我先从宏观上分析一下: 代码主要包含以下几个部分:
- 结构体定义:定义了两个结构体
DictRequest
和DictResponse
,分别用于构造请求数据和解析响应数据。DictRequest
用于构造查询请求的JSON数据,DictResponse
用于解析从API接收到的JSON响应数据。 query
函数:该函数接收一个英文单词作为参数,通过HTTP POST请求向https://api.interpreter.caiyunai.com/v1/dict
地址发送查询请求,并解析返回的JSON数据。它使用http.Client
来执行HTTP请求,并将请求数据编码为JSON格式,并将响应数据解析到DictResponse
结构体中。然后,它输出单词的UK和US发音,并逐行输出单词的释义。main
函数:主函数从命令行参数中获取一个英文单词,然后调用query
函数进行查询。
在具体实现中,query
函数通过构造HTTP请求头和请求体,并调用http.Client
的Do
方法发送POST请求到目标API接口。然后根据HTTP响应状态码判断是否成功获取数据,并将获取到的JSON数据解析到DictResponse
结构体中。
这段代码使用了标准库中的net/http
和encoding/json
包,以及其他一些辅助包用于读取命令行参数和输出结果。它利用第三方API(https://api.interpreter.caiyunai.com/v1/dict
)来查询英文单词的释义和发音。
也许在看这段的时候会遇到很多不懂的名词。什么是API?什么是JSON?什么是HTTP请求?请求头和请求体又是什么?如何发送请求?没关系,我们一个一个来看它:
API:
API是Application Programming Interface(应用程序编程接口)的缩写,它是一组定义了不同软件组件之间交互的规则和协议。API允许不同的应用程序、服务或库之间进行通信和数据交换,使它们能够互相协作,实现特定功能。
API可以看作是应用程序之间的桥梁,通过这个桥梁,应用程序可以相互调用对方提供的功能,获取数据或执行特定操作。API定义了接口的格式和规范,包括请求的数据格式、返回的数据格式、使用的协议等,这使得应用程序的开发者能够很容易地理解和使用其他应用程序的功能。
常见的API类型包括:
- Web API:Web API是一种基于HTTP协议的API,通过URL和HTTP请求方法(如GET、POST、PUT、DELETE等)来调用和传递数据。常见的Web API格式包括RESTful API和SOAP API。
- 库API:库API是一个应用程序库或框架提供的一组函数和数据结构,其他程序可以通过调用这些函数来访问库的功能。
- 操作系统API:操作系统API允许应用程序与操作系统进行交互,以获取系统资源、执行文件操作、处理网络通信等。
- 第三方API:第三方API是由第三方服务提供商开发的API,可以用于获取第三方服务的功能和数据,例如社交媒体API、支付API等。
这个项目中用到的应该是Web API,让我们的程序能够和网站连接。
JSON:
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它是一种文本格式,用于在不同的系统之间进行数据交换。JSON最初由Douglas Crockford提出,并在ECMA-404标准中进行了规范。
缩句:JSON是格式,方便我们传递信息。然后在go语言中,JSON格式和结构体格式是可以互相转化的,通过json.Marshal来实现。
HTTP请求:
HTTP请求是客户端向服务器发送请求以获取或操作资源的过程。HTTP(Hypertext Transfer Protocol)是一种用于传输超文本的协议,是Web通信的基础。HTTP请求由客户端发起,服务器接收并响应请求。
HTTP请求由两部分组成:请求头和请求体。
-
请求头(Request Header):请求头包含了客户端发送给服务器的一些元信息,用于描述请求的属性和要求。常见的请求头包括:
- HTTP方法:GET、POST、PUT、DELETE等,表示请求的类型。
- 请求的URL:用于指定请求的资源地址。
- Host:指定请求的目标服务器的主机名和端口号。
- User-Agent:指定客户端的类型和版本信息。
- Accept:指定客户端可以接收的数据类型。
- Content-Type:指定请求体中的数据类型。
- Authorization:用于认证客户端的身份。
- 等等
-
请求体(Request Body):请求体包含了客户端发送给服务器的实际数据。它通常用于在POST、PUT等请求方法中传递表单数据、JSON数据、文件上传等内容。
发起HTTP请求的过程通常由客户端(浏览器、移动应用或其他应用程序)发起,服务器接收并处理请求,并返回相应的响应数据。客户端通过HTTP请求与服务器进行交互,请求资源、提交数据等。
在不同编程语言中,可以使用相应的HTTP库或框架来发起HTTP请求。例如,在Go语言中可以使用net/http
包来发起HTTP请求,Python中可以使用requests
库,JavaScript中可以使用fetch
或XMLHttpRequest
来发送HTTP请求。
在这个项目中,是通过
js
resp, err := client.Do(req)
来发送请求的。
resp, err := client.Do(req)
是Go语言中使用net/http
包进行HTTP请求的常见用法。
在这行代码中,client
是一个 http.Client
类型的实例,用于执行HTTP请求。http.Client
是Go语言中用于发送HTTP请求的客户端对象,提供了执行GET、POST、PUT等请求的方法。
req
是一个 http.Request
类型的实例,表示一个HTTP请求。在这里,req
是之前创建的一个 POST
请求对象,包含了请求的URL、请求方法、请求头和请求体等信息。
client.Do(req)
会发送 HTTP 请求,并返回一个 *http.Response
类型的响应对象 resp
和一个 error
类型的错误信息 err
。
在实际应用中,通常需要检查 err
是否为 nil
,以确定请求是否成功。如果请求成功,可以通过 resp
来获取响应的内容,响应状态码,以及其他相关信息。
明白了这些概念,再回去看代码,再结合整个宏观架构来看,是不是清晰了许多呢? :)
心得
1.老师在定义两个结构体DictRequest
和DictResponse
,分别用于构造请求数据和解析响应数据的时候,用了两个工具:Convert curl commands to Go (curlconverter.com)和JSON转Golang Struct - 在线工具 - OKTools。这启示我们在工作中可以利用适当的工具减少工作量。 2.对于初学者,有些不懂的库和不懂的代码,可以问ChatGPT,它会给你很详细的解答。(P.S.我这文章有些专业部分也是请教ChatGPT的。不得不说,这大大减少了我找资料的时间)
3.- 一个学习小心得:听课的时候可以边看他的PPT。他的PPT(尤其是注释)写的很详细。(bytedance.feishu.cn/file/boxcnD...