Go语言原理与实践-实战小案例2-在线词典

犀利的毛毛虫 发布于 2025-01-30 231 次阅读


在这个例子中,我们将学习如何使用Go语言来发送http请求、解析json、学习如何使用代码生成来提高开发效率

package main  
  
import (  
    "fmt"  
    "io/ioutil"    "log"    "net/http"    "strings")  
  
func main() {  
    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("accept", "application/json, text/plain, */*")  
	req.Header.Set("accept-language", "zh")  
	req.Header.Set("app-name", "xiaoyi")  
	req.Header.Set("authorization", "Bearer")  
	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("priority", "u=1, i")  
	req.Header.Set("referer", "https://fanyi.caiyunapp.com/")  
	req.Header.Set("sec-ch-ua", `"Microsoft Edge";v="131", "Chromium";v="131", "Not_A Brand";v="24"`)  
	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/131.0.0.0 Safari/537.36 Edg/131.0.0.0")  
	req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi")
    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)  
    }  
    fmt.Printf("%s\n", bodyText)  
}

req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data) 创建了一个httpRequest请求,是向url发送一个POST请求,内容是data,返回的是网站的返回响应数据以及error。resp, err := client.Do(req)是真正发起请求。difer用来手动关闭一个流,他会在函数结束后从下往上触发。

package main  
  
import (  
    "bytes"  
    "encoding/json"    "fmt"    "io/ioutil"    "log"    "net/http")  
  
type DictRequest struct {  
    TransType string `json:"trans_type"`  
    Source    string `json:"source"`  
    UserID    string `json:"user_id"`  
}  
  
func main() {  
    client := &http.Client{}  
    request := DictRequest{TransType: "en2zh", Source: "good"}  
    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("accept", "application/json, text/plain, */*")  
	req.Header.Set("accept-language", "zh")  
	req.Header.Set("app-name", "xiaoyi")  
	req.Header.Set("authorization", "Bearer")  
	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("priority", "u=1, i")  
	req.Header.Set("referer", "https://fanyi.caiyunapp.com/")  
	req.Header.Set("sec-ch-ua", `"Microsoft Edge";v="131", "Chromium";v="131", "Not_A Brand";v="24"`)  
	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/131.0.0.0 Safari/537.36 Edg/131.0.0.0")  
	req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi")
    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)  
    }  
    fmt.Printf("%s\n", bodyText)  
}

运行上述代码会返回一段json,这是需要使用代码生成功能(JSON-to-Go: Convert JSON to Go instantly)将返回的json转换成Go中的Struct:

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      []any      `json:"related"`  
       Source       string     `json:"source"`  
    } `json:"dictionary"`  
}

并在之前代码的后面加上一段将返回的json反序列化到struct里面的代码:

var dictResponse DictResponse  
err = json.Unmarshal(bodyText, &dictResponse)  
if err != nil {  
    log.Fatal(err)  
}  
fmt.Printf("%#v\n", dictResponse)

输出如下:

main.DictResponse{Rc:0, Wiki:struct {}{}, 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\"" }{Prons:struct { EnUs string "json:\"en-us\""; En string "json:\"en\"" }{EnUs:"[gʊd]", En:"[gud]"}, Explanations:[]string{"a.好的;善良的;快乐的;真正的;宽大的;有益的;老练的;幸福的;忠实的;优秀的;完整的;彻底的;丰富的", "n.利益;好处;善良;好人", "ad.=well"}, Synonym:[]string{"excellent", "fine", "nice", "splendid", "proper"}, Antonym:[]string{"bad", "wrong", "evil", "harmful", "poor"}, WqxExample:[][]string{[]string{"to the good", "有利,有好处"}, []string{"good, bad and indifferent", "好的,坏的和一般的"}, []string{"good innings", "长寿"}, []string{"good and ...", "很,颇;完全,彻底"}, []string{"do somebody's heart good", "对某人的心脏有益,使某人感到愉快"}, []string{"do somebody good", "对某人有益"}, []string{"be good for", "对…有效,适合,胜任"}, []string{"be good at", "在…方面(学得,做得)好;善于"}, []string{"as good as one's word", "信守诺言,值得信赖"}, []string{"as good as", "实际上,几乎等于"}, []string{"all well and good", "也好,还好,很不错"}, []string{"a good", "相当,足足"}, []string{"He is good at figures . ", "他善于计算。"}}, Entry:"good", Type:"word", Related:[]interface {}{}, Source:"wenquxing"}}

最后,将整个过程封装为一个函数,传入参数word,并且在主函数中判断os.Args中是否有两个参数,如果有,就代表有单词传入,取os.Args[1],传入query()方法中即可。下面是全部代码:

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 {  
    } `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      []any      `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("accept", "application/json, text/plain, */*")  
	req.Header.Set("accept-language", "zh")  
	req.Header.Set("app-name", "xiaoyi")  
	req.Header.Set("authorization", "Bearer")  
	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("priority", "u=1, i")  
	req.Header.Set("referer", "https://fanyi.caiyunapp.com/")  
	req.Header.Set("sec-ch-ua", `"Microsoft Edge";v="131", "Chromium";v="131", "Not_A Brand";v="24"`)  
	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/131.0.0.0 Safari/537.36 Edg/131.0.0.0")  
	req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi")
    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))  
    }  
  
    //fmt.Printf("%s\n", bodyText)  
    var dictResponse DictResponse  
    err = json.Unmarshal(bodyText, &dictResponse)  
    if err != nil {  
       log.Fatal(err)  
    }  
  
    fmt.Println(word, "\nUK:", 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)  
}

你也可以改为在程序里输入word来查询单词:

reader := bufio.NewReader(os.Stdin)  
fmt.Print("Enter word or phrase: ")  
input, _ := reader.ReadString('\n')  
input = strings.TrimSuffix(input, "\n")  
query(input)