Go语言入门-工程实践 | 青训营笔记

154 阅读13分钟

这是我参与[第五届青训营]伴学笔记创作活动的第1天

一、修改第一个例子猜谜游戏里面的最终代码,使用fmt.Scanf来简化代码实现

引入fmt.Scanf()后,把原有的定义io流输入的代码删除,把判断是否是整数的代码删除,得到的代码如下:

 package main
 ​
 import (
     "fmt"
     "math/rand"
     "time"
 )
 ​
 func main() {
     maxNum := 100
     rand.Seed(time.Now().UnixNano())
     secretNumber := rand.Intn(maxNum)
     // fmt.Println("The secret number is ", secretNumber)
 ​
     fmt.Println("Please input your guess")
     var input int
     for {
 ​
         fmt.Scanf("%d",&input)
 ​
         fmt.Println("You guess is", input)
         if input > secretNumber {
             fmt.Println("Your guess is bigger than the secret number. Please try again")
         } else if input < secretNumber {
             fmt.Println("Your guess is smaller than the secret number. Please try again")
         } else {
             fmt.Println("Correct, you Legend!")
             break
         }
     }
 }

二、构造一个在线词典,实现英文中翻英

具体要求:

运行程序时,在go run命令后加上一个英文单词,要求翻译这个英文单词

实现效果如下:

image-20230122210224034

1·实现思路:

在goland发送请求,然后处理服务器返回的响应,输出要求的内容

2·实现步骤:

a构造一个请求

打开彩云小译,使用F12,复制dict中的cURL,然后使用代码生成网站[curlconverter.com#go]:cURL转化为一个go语言写的请求,输入复制的cURL,生 成go语言写的请求

image-20230122211328613

image-20230122211459488

生成的请求代码

 package main
 ​
 import (
     "fmt"
     "io/ioutil"
     "log"
     "net/http"
     "strings"
 )
 ​
 func main() {
     //创建一个HTTP client
     client := &http.Client{}
 ​
     var data = strings.NewReader(`{"trans_type":"en2zh","source":"good"}`)
 ​
     //创建请求
     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)
     }
 ​
     //打印响应(响应是json)
     fmt.Printf("%s\n", bodyText)
 }

运行结果如下:

image-20230122211613596

如图,服务器返回了一条JSON,序列化

b解析response body

在golang中,一般会写一个结构体,把返回的json反序列化到结构体里面。复制这个json,使用网站[oktools.net/json2go]:json转化为go语言写的结构体。

image-20230122213315798

生成的Golang Struct

 type AutoGenerated 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"`
 }

b 最后的处理及代码完善

1·取结构体中的部分值,输出音标和翻译

2·加入命令行输入的代码,支持输入随机单词

最终代码如下:

 package main
 ​
 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) {
     //创建一个HTTP client
     client := &http.Client{}
 ​
     //请求结构体声明定义
     request := DictRequest{TransType: "en2zh", Source: word}
 ​
     //把请求结构体序列化为json格式
     buf, err := json.Marshal(request)
     if err != nil {
         log.Fatal(err)
     }
 ​
     //把json转化为byte格式,作为body传给http请求
     var data = bytes.NewReader(buf)
 ​
     //建立一个http请求,函数参数分别为:请求方法,url链接,body
     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()
 ​
     //读取响应,注意响应为byte格式
     bodyText, err := ioutil.ReadAll(resp.Body)
     if err != nil {
         log.Fatal(err)
     }
 ​
     //判断状态码是否为200
     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() {
     //判断命令行参数是否为2,前面是运行命令,后面是所要翻译的单词
     if len(os.Args) != 2 {
         fmt.Fprintf(os.Stderr, `usage: simpleDict WORD
 example: simpleDict hello
         `)
         os.Exit(1)
     }
     //取所要翻译的单词,使用query()函数进行翻译
     word := os.Args[1]
     query(word)
 }

代码总体思路为:

先通过命令行输入程序执行命令及所要翻译的单词;然后把这个单词和翻译类型一起储存在请求结构体中;接着把这个结构体序列化为json格式,并把转化后的json转化为byte格式;然后建立http请求,参数分别为post,url,和翻译类型;再接着设置请求头的内容;然后发起请求;接着读取服务器的响应,并且判断状态码;然后把响应内容发序列化在响应结构体中;最后输出结构体中的音标和翻译内容。

三、实战演练1

要求:修改第二个例子命令行词典里面的最终代码,增加另一种翻译引擎的支持。

实现思路:

参考第二个例子,选择有道翻译,然后复制它的curl生成请求,接着根据请求输出的json生成响应结构体,分析这个结构体,保留音标和中文翻译的内容,然后输出。在main函数中,用if来做一个选择。最终代码可以支持两种翻译引擎。

代码:

 package main
 ​
 import (
     "bytes"
     "encoding/json"
     "fmt"
     "io/ioutil"
     "log"
     "net/http"
     "os"
     "strings"
 )
 ​
 type DictRequest struct {
     TransType string `json:"trans_type"`
     Source    string `json:"source"`
     UserID    string `json:"user_id"`
 }
 ​
 //响应结构体
 type DictResponse1 struct {
     Rc   int `json:"rc"`
     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"`
 }
 ​
 ​
 ​
 type DictResponse struct {
     Simple struct {
         Query string `json:"query"`
         Word []struct {
             Usphone string `json:"usphone"`
             Ukphone string `json:"ukphone"`
             Ukspeech string `json:"ukspeech"`
             ReturnPhrase string `json:"return-phrase"`
             MultiPhone struct {
                 Uk []struct {
                     Phone string `json:"phone"`
                     Pos []string `json:"pos"`
                     Speech string `json:"speech"`
                 } `json:"uk"`
                 Us []struct {
                     Phone string `json:"phone"`
                     Pos []string `json:"pos"`
                     Speech string `json:"speech"`
                 } `json:"us"`
             } `json:"multiPhone"`
             Usspeech string `json:"usspeech"`
         } `json:"word"`
     } `json:"simple"`
     Ec struct {
         WebTrans []string `json:"web_trans"`
         ExamType []string `json:"exam_type"`
         Source struct {
             Name string `json:"name"`
             URL string `json:"url"`
         } `json:"source"`
         Word struct {
             Usphone string `json:"usphone"`
             Ukphone string `json:"ukphone"`
             Ukspeech string `json:"ukspeech"`
             Trs []struct {
                 Pos string `json:"pos,omitempty"`
                 Tran string `json:"tran"`
             } `json:"trs"`
             Wfs []struct {
                 Wf struct {
                     Name string `json:"name"`
                     Value string `json:"value"`
                 } `json:"wf"`
             } `json:"wfs"`
             ReturnPhrase string `json:"return-phrase"`
             Usspeech string `json:"usspeech"`
         } `json:"word"`
     } `json:"ec"`
 ​
 }
 ​
 func query1(word string) {
     //创建一个HTTP client
     client := &http.Client{}
 ​
     //请求结构体声明定义
     request := DictRequest{TransType: "en2zh", Source: word}
 ​
     //把请求结构体序列化为json格式
     buf, err := json.Marshal(request)
     if err != nil {
         log.Fatal(err)
     }
 ​
     //把json转化为byte格式,作为body传给http请求
     var data = bytes.NewReader(buf)
 ​
     //建立一个http请求,函数参数分别为:请求方法,url链接,body
     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()
 ​
     //读取响应,注意响应为byte格式
     bodyText, err := ioutil.ReadAll(resp.Body)
     if err != nil {
         log.Fatal(err)
     }
 ​
     //判断状态码是否为200
     if resp.StatusCode != 200 {
         log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))
     }
 ​
 ​
     //把响应内容反序列化在响应结构体中
     var dictResponse DictResponse1
     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 query2(word string) {
     client := &http.Client{}
 ​
     str:=`&le=en&t=1&client=web&sign=c3849459051233f11a5546dc790f6b4e&keyfrom=webdict`
     te:=`q=`
     str=te+word+str
     var data = strings.NewReader(str)
 ​
     //request:=DictRequest{Q:word,Le:"en",T:1,Client: "web",Sign:"c3849459051233f11a5546dc790f6b4e",Keyfrom: "webdict"}
     //
     //buf,err:=json.Marshal(request)
     //
     //if err!=nil{
     //  log.Fatal(err)
     //}
     //
     //var data=bytes.NewReader(buf)
 ​
 ​
     req, err := http.NewRequest("POST", "https://dict.youdao.com/jsonapi_s?doctype=json&jsonversion=4", data)
     if err != nil {
         log.Fatal(err)
     }
     req.Header.Set("Accept", "application/json, text/plain, */*")
     req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,en-GB;q=0.6,en-GB-oxendict;q=0.5")
     req.Header.Set("Connection", "keep-alive")
     req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
     req.Header.Set("Cookie", "OUTFOX_SEARCH_USER_ID=-1596569195@2408:8456:7e31:8088:705b:c538:d03:288f; OUTFOX_SEARCH_USER_ID_NCOO=1082763168.642713; _ntes_nnid=183eae8e70cee712418938f4c3a30ec0,1628690979922; YOUDAO_MOBILE_ACCESS_TYPE=0")
     req.Header.Set("Origin", "https://www.youdao.com")
     req.Header.Set("Referer", "https://www.youdao.com/")
     req.Header.Set("Sec-Fetch-Dest", "empty")
     req.Header.Set("Sec-Fetch-Mode", "cors")
     req.Header.Set("Sec-Fetch-Site", "same-site")
     req.Header.Set("User-Agent", "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Mobile Safari/537.36 Edg/109.0.1518.61")
     req.Header.Set("sec-ch-ua", `"Not_A Brand";v="99", "Microsoft Edge";v="109", "Chromium";v="109"`)
     req.Header.Set("sec-ch-ua-mobile", "?1")
     req.Header.Set("sec-ch-ua-platform", `"Android"`)
     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.Simple.Word[0].Ukphone,"]","US:","[",dictResponse.Simple.Word[0].Usphone,"]")
     for _,item:=range dictResponse.Ec.WebTrans{
         fmt.Println(item)
     }
 }
 ​
 ​
 ​
 func main() {
     //判断命令行参数是否为2,前面是运行命令,后面是所要翻译的单词
     fmt.Println("有两个翻译软件,在输入翻译单词后输出1,代表选彩云小译进行翻译,输入2代表选有道翻译进行翻译:")
     if len(os.Args) != 3 {
         fmt.Fprintf(os.Stderr, `usage: simpleDict WORD
 example: simpleDict hello
         `)
         os.Exit(1)
     }
     se:=os.Args[2]
     word := os.Args[1]
     if se=="1"{
         fmt.Println("选择了彩云小译:")
         query1(word)
     }else {
         fmt.Println("选择了有道翻译:")
         query2(word)
     }
 }

注意:在query2()函数里面,用字符串代替json操作进行body参数的传递,后续可使用json.marshaler去序列化这个参数,以提高传输速度。

(推测:使用结构体序列化为json时,需要对body参数对应的那个字符串里面的特殊字符&进行处理)

四、实战演练2

要求:在上一个步骤的基础上,修改代码实现并行请求两个翻译引擎来提高响应速度

实现思路:

make一个chan,然后开两个goroutine,把这个chan作为参数传给query1()和query()2函数,接着用<-ch阻塞main()函数,直到收到通道里面传来的信息

 package main
 ​
 import (
     "bytes"
     "encoding/json"
     "fmt"
     "io/ioutil"
     "log"
     "net/http"
     "os"
     "strings"
 )
 ​
 type DictRequest struct {
     TransType string `json:"trans_type"`
     Source    string `json:"source"`
     UserID    string `json:"user_id"`
 }
 ​
 //响应结构体
 type DictResponse1 struct {
     Rc   int `json:"rc"`
     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"`
 }
 ​
 ​
 ​
 type DictResponse struct {
     Simple struct {
         Query string `json:"query"`
         Word []struct {
             Usphone string `json:"usphone"`
             Ukphone string `json:"ukphone"`
             Ukspeech string `json:"ukspeech"`
             ReturnPhrase string `json:"return-phrase"`
             MultiPhone struct {
                 Uk []struct {
                     Phone string `json:"phone"`
                     Pos []string `json:"pos"`
                     Speech string `json:"speech"`
                 } `json:"uk"`
                 Us []struct {
                     Phone string `json:"phone"`
                     Pos []string `json:"pos"`
                     Speech string `json:"speech"`
                 } `json:"us"`
             } `json:"multiPhone"`
             Usspeech string `json:"usspeech"`
         } `json:"word"`
     } `json:"simple"`
     Ec struct {
         WebTrans []string `json:"web_trans"`
         ExamType []string `json:"exam_type"`
         Source struct {
             Name string `json:"name"`
             URL string `json:"url"`
         } `json:"source"`
         Word struct {
             Usphone string `json:"usphone"`
             Ukphone string `json:"ukphone"`
             Ukspeech string `json:"ukspeech"`
             Trs []struct {
                 Pos string `json:"pos,omitempty"`
                 Tran string `json:"tran"`
             } `json:"trs"`
             Wfs []struct {
                 Wf struct {
                     Name string `json:"name"`
                     Value string `json:"value"`
                 } `json:"wf"`
             } `json:"wfs"`
             ReturnPhrase string `json:"return-phrase"`
             Usspeech string `json:"usspeech"`
         } `json:"word"`
     } `json:"ec"`
 ​
 }
 ​
 func query1(word string,ch chan int) {
 ​
     //创建一个HTTP client
     client := &http.Client{}
 ​
     //请求结构体声明定义
     request := DictRequest{TransType: "en2zh", Source: word}
 ​
     //把请求结构体序列化为json格式
 ​
     buf, err := json.Marshal(request)
     if err != nil {
         log.Fatal(err)
     }
 ​
     //把json转化为byte格式,作为body传给http请求
     var data = bytes.NewReader(buf)
 ​
     //建立一个http请求,函数参数分别为:请求方法,url链接,body
     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()
 ​
     //读取响应,注意响应为byte格式
     bodyText, err := ioutil.ReadAll(resp.Body)
     if err != nil {
         log.Fatal(err)
     }
 ​
     //判断状态码是否为200
     if resp.StatusCode != 200 {
         log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))
     }
 ​
 ​
     //把响应内容反序列化在响应结构体中
     var dictResponse DictResponse1
     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)
     }
     ch<-0
 }
 ​
 ​
 func query2(word string,ch chan int) {
 ​
     client := &http.Client{}
 ​
     str:=`&le=en&t=1&client=web&sign=c3849459051233f11a5546dc790f6b4e&keyfrom=webdict`
     te:=`q=`
     str=te+word+str
     var data = strings.NewReader(str)
 ​
     //request:=DictRequest{Q:word,Le:"en",T:1,Client: "web",Sign:"c3849459051233f11a5546dc790f6b4e",Keyfrom: "webdict"}
     //
     //buf,err:=json.Marshal(request)
     //
     //if err!=nil{
     //  log.Fatal(err)
     //}
     //
     //var data=bytes.NewReader(buf)
 ​
 ​
     req, err := http.NewRequest("POST", "https://dict.youdao.com/jsonapi_s?doctype=json&jsonversion=4", data)
     if err != nil {
         log.Fatal(err)
     }
     req.Header.Set("Accept", "application/json, text/plain, */*")
     req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,en-GB;q=0.6,en-GB-oxendict;q=0.5")
     req.Header.Set("Connection", "keep-alive")
     req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
     req.Header.Set("Cookie", "OUTFOX_SEARCH_USER_ID=-1596569195@2408:8456:7e31:8088:705b:c538:d03:288f; OUTFOX_SEARCH_USER_ID_NCOO=1082763168.642713; _ntes_nnid=183eae8e70cee712418938f4c3a30ec0,1628690979922; YOUDAO_MOBILE_ACCESS_TYPE=0")
     req.Header.Set("Origin", "https://www.youdao.com")
     req.Header.Set("Referer", "https://www.youdao.com/")
     req.Header.Set("Sec-Fetch-Dest", "empty")
     req.Header.Set("Sec-Fetch-Mode", "cors")
     req.Header.Set("Sec-Fetch-Site", "same-site")
     req.Header.Set("User-Agent", "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Mobile Safari/537.36 Edg/109.0.1518.61")
     req.Header.Set("sec-ch-ua", `"Not_A Brand";v="99", "Microsoft Edge";v="109", "Chromium";v="109"`)
     req.Header.Set("sec-ch-ua-mobile", "?1")
     req.Header.Set("sec-ch-ua-platform", `"Android"`)
     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.Simple.Word[0].Ukphone,"]","US:","[",dictResponse.Simple.Word[0].Usphone,"]")
     for _,item:=range dictResponse.Ec.WebTrans{
         fmt.Println(item)
     }
     ch<-0
 }
 ​
 ​
 ​
 func main() {
     //判断命令行参数是否为2,前面是运行命令,后面是所要翻译的单词
     ch:=make(chan int)
     if len(os.Args) != 2 {
         fmt.Fprintf(os.Stderr, `usage: simpleDict WORD
 example: simpleDict hello
         `)
         os.Exit(1)
     }
 ​
     word := os.Args[1]
     go query1(word,ch)
     go query2(word,ch)
     <-ch
 ​
 }

总结:

纸上得来终觉浅,绝知此事要躬行。一边看着视频,一遍按着里面的步骤进行操作,遇到问题的时候,总是可以对照着视频里面的内容发现问题所在,从而修改。举例,在实战1中,cURL中代码特殊字符&,不能直接用结构体序列成json。需要对这个字符进行处理或者是换一种方式去写代码。当时对着代码实现的时候没有发现这个问题,以为是自己的代码敲错了,然后在不断地检查代码,后来发不对劲,通过输出检查后发现问题可能出现在json定义这一个步骤中,经过一段时间后的百度搜索,得出结论,当字符串中存在特殊字符时,需要对特殊字符进行处理,不能直接通过结构体赋值转json。

如上,共勉。