Golang实战案例(二) | 青训营笔记

130 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第5天

在线词典

(1). 目标分析

本节课要进行一些较为复杂的代码编写,先进行一个关于英文在线词典的开发,首先看我们要实现一个什么样的在线词典,要求显示类似如下的内容:

go run simpledict/main.go hello

输出为这个单词的相关内容,音标、释义、词性等:

hello UK:['he'lau] US: [ha'lo]
int. 喂;哈罗
n. 引人注意的呼声
v. 向人呼(喂)

想要查询单词的相关信息,需要借助第三方API,同时这里将会涉及JSON解析、HTTP请求、信息显示等一系列的知识点。同时借助代码生成提高开发效率。

(2). 发送请求

本节课借助的是彩云翻译的API,首先该如何获取这个网站的API,需要从浏览器上拿到dict的请求。 这里使用的是Chorme浏览器,通过点击翻译的操作,对带有词典的单词,右键选择检查,我们可以在Network一栏找到dict,点击后,找到method为 POST 字样的dict。
image.png
同样,在下方可以看见该网络操作的请求头和回应头的内容,为 Response Headers 和 Request Headers。可以看出,这个请求的内容很繁多,如果纯手写代码请求将会浪费不必要的时间,因此这里也是要用的代码生成的地方。
image.png
接下来查看 preview 和 payload 的内容,preview展示了单词的相关信息,payload显示了本次翻译的类型和语言,以及源单词。确认是否为类似以下格式的信息,如果是则可以进行下一步。
image.png
image.png
生成所需要的golang请求,首先右键dict -> Copy -> Copy as cRUL (cmd/bash),这里要选择bash,将其复制到命令行窗口,执行后可以发现返回一个json序列。
image.png 得到cRUL命令后,进入网址 curlconverter.com/#go ,这是一个代码生成平台,将请求生成为相应语言的代码。在上面的command栏中粘贴复制的结果,下方会根据语言自动生成,生成可能会有些语法错误,按照下方提示进行修改即可。
image.png
观察得到的代码,首先创建请求,设置变量client是http请求的客户端变量,这里省略了对请求超时时长的设置;使用NewReader对读入的字符串变换为流数据data,便于在内存中的读取防止数据过大造成的问题。设置一个新的请求,请求方式以及请求位置和请求内容等,附加错误检测。

client := &http.Client{}
var data = strings.NewReader(`{"trans_type":"en2zh","source":"procedure"`)
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")
req.Header.Set("app-name", "xy")
req.Header.Set("content-type", "application/json;charset=UTF-8")
req.Header.Set("device-id", "")
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", "Google Chrome";v="109", "Chromium";v="109"`)
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/109.0.0.0 Safari/537.36")
req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi")

接下来调用client.Do()函数发起请求过程,返回一个响应。如遇到网络问题等发生错误,会在错误检测发送日志错误报告并结束程序;如果正常进行则返回一个resp,而为了内存安全这里需要用defer在函数结束时从下向上调用所有defer来关闭流:

resp, err := client.Do(req)
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()

最后是对得到的响应内容输出验证,将数据流转换为字符串,如果成功将会输出一串json字符串,否则发生错误。

bodyText, err := ioutil.ReadAll(resp.Body)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("%s\n", bodyText)