当前位置:   article > 正文

Go语言实战案例_go实战项目

go实战项目

一.猜题游戏-生成随机数

1.0 生成随机数

  1. package main
  2. import (
  3. "fmt"
  4. "math/rand"
  5. )
  6. func main() {
  7. maxNum := 100
  8. secretNumber := rand.Intn(maxNum)
  9. fmt.Println("The secret number is", secretNumber)
  10. }

发现每次都会打印相同数字在屏幕上(81)

开发环境可能可以打印出不同的数字(但不推荐1.0)

我们可以查看 这个包的文档。文档的开头的例子告诉我们使用它之前需要设置随机数种子,否则的话每一次都会生成相同的随机数序列。一般惯例用法是在程序启动的时候,用启动的时间戳来初始化随机数种子,我们用 time.Now().UnixNano() 来初始化随机种子。

1.1

  1. package main
  2. import (
  3. "fmt"
  4. "math/rand"
  5. "time"
  6. )
  7. func main() {
  8. maxNum := 100
  9. rand.Seed(time.Now().UnixNano()) // 设置随机数种子
  10. secretNumber := rand.Intn(maxNum)
  11. fmt.Println("The secret number is ", secretNumber)
  12. }

结果会是在 0 到 100 之间

2.0 读取用户输入

  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "math/rand"
  6. "os"
  7. "strconv"
  8. "strings"
  9. "time"
  10. )
  11. func main() {
  12. maxNum := 100
  13. rand.Seed(time.Now().UnixNano()) // 设置随机数种子
  14. secretNumber := rand.Intn(maxNum)
  15. fmt.Println("The secret number is ", secretNumber)
  16. fmt.Println("Please input your guess")
  17. reader := bufio.NewReader(os.Stdin) //把一个文件转换成一个 reader 变量
  18. input, err := reader.ReadString('\n') //读取一行
  19. if err != nil {
  20. fmt.Println("An error occured while reading input. Please try again", err)
  21. return
  22. }
  23. input = strings.TrimSuffix(input, "\n") // 去掉换行符,注意Mac\n,windows自动加入的是\r\n
  24. guess, err := strconv.Atoi(input) // 将字符串转换成数字
  25. if err != nil {
  26. fmt.Println("Invalid input. Please enter an integer value")
  27. return
  28. }
  29. fmt.Println("You guess is", guess)
  30. }

每个程序执行的时候都会打开几个文件,stdin stdout stderr等,stdin 文件可以用 os.Stdin 来得到。

然后直接操作这个文件很不方便,我们会用 bufio.NewReader 把一个文件转换成一个 reader 变量。

reader 变量上会有很多用来操作一个流的操作,我们可以用它的 ReadString 方法来读取一行。

如果失败了的话,我们会打印错误并能退出。ReadString 返回的结果包含结尾的回车符和换行符,去掉,再用strconv.Atoi()转换成数字。如果转换失败,我们同样打印错误,退出。

3.0 实现判断逻辑

  1. if guess > secretNumber {
  2. fmt.Println("Your guess is bigger than the secret number. Please try again")
  3. } else if guess < secretNumber {
  4. fmt.Println("Your guess is smaller than the secret number. Please try again")
  5. } else {
  6. fmt.Println("Correct, you Legend!")
  7. }

4.0 完整的游戏

  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "math/rand"
  6. "os"
  7. "strconv"
  8. "strings"
  9. "time"
  10. )
  11. func main() {
  12. maxNum := 100
  13. rand.Seed(time.Now().UnixNano()) // 设置随机数种子
  14. secretNumber := rand.Intn(maxNum)
  15. // fmt.Println("The secret number is ", secretNumber)
  16. fmt.Println("Please input your guess")
  17. reader := bufio.NewReader(os.Stdin) //把一个文件转换成一个 reader 变量
  18. for {
  19. input, err := reader.ReadString('\n') //读取一行
  20. if err != nil {
  21. fmt.Println("An error occured while reading input. Please try again", err)
  22. continue
  23. }
  24. input = strings.TrimSuffix(input, "\n") // 去掉换行符
  25. guess, err := strconv.Atoi(input) // 将字符串转换成数字
  26. if err != nil {
  27. fmt.Println("Invalid input. Please enter an integer value")
  28. continue
  29. }
  30. fmt.Println("You guess is", guess)
  31. if guess > secretNumber {
  32. fmt.Println("Your guess is bigger than the secret number. Please try again")
  33. } else if guess < secretNumber {
  34. fmt.Println("Your guess is smaller than the secret number. Please try again")
  35. } else {
  36. fmt.Println("Correct, you Legend!")
  37. break
  38. }
  39. }
  40. }

 二.在线词典

1.准备(以Google浏览器,Mac系统操作)

首先打开网址:彩云小译-网页翻译-文献翻译-在线翻译

查询一个单词,通过调用第三方的 API 查询到单词的翻译并打印出来。

在这个项目里面,学习如何用 go 语言来发送 HTTP 请求、解析 json,学习了如何使用代码生成来提高开发效率

2.抓包

要用到的 API 是彩云在线翻译,以此为例

点击翻译,浏览器会发送一系列请求,找到查询单词的请求。这是一个 HTTP 的 post 的请求(相当复杂),请求的 header 是一个 json,里面有两个字段,代表要翻译的语言和查询的单词,source就是要查询的词。API 的返回结果里面会有 Wiki 和 dictionary 两个字段。需要用的结果主要在 dictionary.Explanations 字段里面,其他字段里面还包括音标等信息。

 

3.代码生成

  1. curl 'https://api.interpreter.caiyunai.com/v1/translator' \
  2. -X 'OPTIONS' \
  3. -H 'authority: api.interpreter.caiyunai.com' \
  4. -H 'accept: */*' \
  5. -H 'accept-language: zh-CN,zh;q=0.9' \
  6. -H 'access-control-request-headers: app-name,content-type,device-id,os-type,os-version,t-authorization,version,x-authorization' \
  7. -H 'access-control-request-method: POST' \
  8. -H 'origin: https://fanyi.caiyunapp.com' \
  9. -H 'referer: https://fanyi.caiyunapp.com/' \
  10. -H 'sec-fetch-dest: empty' \
  11. -H 'sec-fetch-mode: cors' \
  12. -H 'sec-fetch-site: cross-site' \
  13. -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' \
  14. --compressed ;
  15. curl 'https://api.interpreter.caiyunai.com/v1/translator' \
  16. -H 'authority: api.interpreter.caiyunai.com' \
  17. -H 'accept: application/json, text/plain, */*' \
  18. -H 'accept-language: zh-CN,zh;q=0.9' \
  19. -H 'app-name: xy' \
  20. -H 'content-type: application/json;charset=UTF-8' \
  21. -H 'device-id: 5107a8a7278db425e7bce568842b1261' \
  22. -H 'origin: https://fanyi.caiyunapp.com' \
  23. -H 'os-type: web' \
  24. -H 'os-version;' \
  25. -H 'referer: https://fanyi.caiyunapp.com/' \
  26. -H 'sec-ch-ua: "Not.A/Brand";v="8", "Chromium";v="114", "Google Chrome";v="114"' \
  27. -H 'sec-ch-ua-mobile: ?0' \
  28. -H 'sec-ch-ua-platform: "macOS"' \
  29. -H 'sec-fetch-dest: empty' \
  30. -H 'sec-fetch-mode: cors' \
  31. -H 'sec-fetch-site: cross-site' \
  32. -H 't-authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJicm93c2VyX2lkIjoiNTEwN2E4YTcyNzhkYjQyNWU3YmNlNTY4ODQyYjEyNjEiLCJpcF9hZGRyZXNzIjoiMjIzLjcyLjU1LjMxIiwidG9rZW4iOiJxZ2VtdjRqcjF5MzhqeXE2dmh2aSIsInZlcnNpb24iOjEsImV4cCI6MTY5MDM2NjQ1Nn0.CJyHVaSyAKSfVjtRlXx4trDK57TvhLAewH-rkhQWrag' \
  33. -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' \
  34. -H 'x-authorization: token:qgemv4jr1y38jyq6vhvi' \
  35. --data-raw '{"source":"good","trans_type":"auto2zh","request_id":"web_fanyi","media":"text","os_type":"web","dict":true,"cached":true,"replaced":true,"style":"formal","detect":true,"browser_id":"5107a8a7278db425e7bce568842b1261"}' \
  36. --compressed ;
  37. curl 'https://api.interpreter.caiyunai.com/v1/dict' \
  38. -X 'OPTIONS' \
  39. -H 'authority: api.interpreter.caiyunai.com' \
  40. -H 'accept: */*' \
  41. -H 'accept-language: zh-CN,zh;q=0.9' \
  42. -H 'access-control-request-headers: app-name,content-type,device-id,os-type,os-version,version,x-authorization' \
  43. -H 'access-control-request-method: POST' \
  44. -H 'origin: https://fanyi.caiyunapp.com' \
  45. -H 'referer: https://fanyi.caiyunapp.com/' \
  46. -H 'sec-fetch-dest: empty' \
  47. -H 'sec-fetch-mode: cors' \
  48. -H 'sec-fetch-site: cross-site' \
  49. -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' \
  50. --compressed ;
  51. curl 'https://api.interpreter.caiyunai.com/v1/dict' \
  52. -H 'authority: api.interpreter.caiyunai.com' \
  53. -H 'accept: application/json, text/plain, */*' \
  54. -H 'accept-language: zh-CN,zh;q=0.9' \
  55. -H 'app-name: xy' \
  56. -H 'content-type: application/json;charset=UTF-8' \
  57. -H 'device-id: 5107a8a7278db425e7bce568842b1261' \
  58. -H 'origin: https://fanyi.caiyunapp.com' \
  59. -H 'os-type: web' \
  60. -H 'os-version;' \
  61. -H 'referer: https://fanyi.caiyunapp.com/' \
  62. -H 'sec-ch-ua: "Not.A/Brand";v="8", "Chromium";v="114", "Google Chrome";v="114"' \
  63. -H 'sec-ch-ua-mobile: ?0' \
  64. -H 'sec-ch-ua-platform: "macOS"' \
  65. -H 'sec-fetch-dest: empty' \
  66. -H 'sec-fetch-mode: cors' \
  67. -H 'sec-fetch-site: cross-site' \
  68. -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' \
  69. -H 'x-authorization: token:qgemv4jr1y38jyq6vhvi' \
  70. --data-raw '{"trans_type":"en2zh","source":"good"}' \
  71. --compressed

打开代码生成网址:

 Convert curl commands to Go

将复制的粘贴过来,自动生成 Golang 代码

需要在 Golang 里面去发送这个请求。但是这个请求比较复杂,用代码构造很麻烦。可以用一种简单的方式来生成代码,右键浏览器里面的 copy as curl,在终端粘贴一下 curl 命令,可以返回一大串 json。

4.生成代码解读

5.生成request body/解析request body

在 Golang 里面,需要生成一段 JSON ,常用的方式是先构造出来一个结构体,这个结构体和需要生成的 JSON 的结构是一一对应的。

通过该网站转换结构体

JSON转Golang Struct - 在线工具 - OKTools

将Preview中复制过来转换成结构体

 完整代码展示:

  1. package main
  2. import (
  3. "bufio"
  4. "bytes"
  5. "encoding/json"
  6. "fmt"
  7. "io"
  8. "log"
  9. "net/http"
  10. "os"
  11. "strings"
  12. "sync"
  13. )
  14. var wg sync.WaitGroup
  15. type DictRequestCY struct {
  16. TransType string `json:"trans_type"`
  17. Source string `json:"source"`
  18. UserID string `json:"user_id"`
  19. }
  20. type DictResponseCY struct {
  21. Rc int `json:"rc"`
  22. Wiki struct {
  23. KnownInLaguages int `json:"known_in_laguages"`
  24. Description struct {
  25. Source string `json:"source"`
  26. Target interface{} `json:"target"`
  27. } `json:"description"`
  28. ID string `json:"id"`
  29. Item struct {
  30. Source string `json:"source"`
  31. Target string `json:"target"`
  32. } `json:"item"`
  33. ImageURL string `json:"image_url"`
  34. IsSubject string `json:"is_subject"`
  35. Sitelink string `json:"sitelink"`
  36. } `json:"wiki"`
  37. Dictionary struct {
  38. Prons struct {
  39. EnUs string `json:"en-us"`
  40. En string `json:"en"`
  41. } `json:"prons"`
  42. Explanations []string `json:"explanations"`
  43. Synonym []string `json:"synonym"`
  44. Antonym []string `json:"antonym"`
  45. WqxExample [][]string `json:"wqx_example"`
  46. Entry string `json:"entry"`
  47. Type string `json:"type"`
  48. Related []interface{} `json:"related"`
  49. Source string `json:"source"`
  50. } `json:"dictionary"`
  51. }
  52. type DictResponseBD struct {
  53. Errno int `json:"errno"`
  54. Data []struct {
  55. K string `json:"k"`
  56. V string `json:"v"`
  57. } `json:"data"`
  58. }
  59. func queryBD(word string) {
  60. client := &http.Client{}
  61. var data = strings.NewReader("kw=" + word)
  62. req, err := http.NewRequest("POST", "https://fanyi.baidu.com/sug", data)
  63. if err != nil {
  64. log.Fatal(err)
  65. }
  66. req.Header.Set("Accept", "application/json, text/javascript, */*; q=0.01")
  67. 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")
  68. req.Header.Set("Connection", "keep-alive")
  69. req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
  70. req.Header.Set("Cookie", "BIDUPSID=1CDF4C78BCFB3D90B2D6A594920DA6E4; PSTM=1630726121; __yjs_duid=1_02f9d28d226309370f287ee032114e3f1630763189674; REALTIME_TRANS_SWITCH=1; HISTORY_SWITCH=1; FANYI_WORD_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; BAIDUID=396D4FB45E415311D3C31A0DE0D1AF80:FG=1; BDUSS=V6NWkyMzJnaTB-OWplSFdUR25tRkxsTzFnVnBDanN4ZEs2bHFMc2EzaXJOcDVrRVFBQUFBJCQAAAAAAAAAAAEAAACpaydUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKupdmSrqXZkMV; BDUSS_BFESS=V6NWkyMzJnaTB-OWplSFdUR25tRkxsTzFnVnBDanN4ZEs2bHFMc2EzaXJOcDVrRVFBQUFBJCQAAAAAAAAAAAEAAACpaydUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKupdmSrqXZkMV; APPGUIDE_10_6_2=1; MCITY=-75%3A; MAWEBCUID=web_jcjIPqwGUVRAlyJeYpGiILrRIWXcMWNDAjChgRXUZoHLpLyApr; BDRCVFR[feWj1Vr5u3D]=I67x6TjHwwYf0; delPer=0; PSINO=1; BAIDUID_BFESS=396D4FB45E415311D3C31A0DE0D1AF80:FG=1; BA_HECTOR=2h852l8h2ha5840k8k0k050g1iai2fd1o; ZFY=kYWZ1Y6d6SV8cMcgDFNKAhwEEhlIK7W5gu1C:APN07HM:C; H_PS_PSSID=36546_39026_39022_38858_38957_38954_39009_38918_38972_38815_38637_26350_39041_38948_39046; ab_sr=1.0.1_MjBiYTAxMmUwMWE2MzIyODYxY2JiYzIxNjFjMWY2OTIwOTc5NTA1MTI5MzAzZGI2OWNiMGEwM2I1Y2IwNjJiZWEzNDQwOTg1ZTkyYTJkNmU1OTc3MjY1MTJhZTM1MGEwNWNlM2NkM2VjNWM0NDMwZjY0ZWJlZTEyOTQyZjFkZjE1YzhiYzY4YjBhYzQ4NzE2NWI4MjNkZjA1NTVkMDk2MmRjMjZhYTA4NThmOTYwMmEzOWMxMjAxMGM2OTdjODhm")
  71. req.Header.Set("Origin", "https://fanyi.baidu.com")
  72. req.Header.Set("Referer", "https://fanyi.baidu.com/")
  73. req.Header.Set("Sec-Fetch-Dest", "empty")
  74. req.Header.Set("Sec-Fetch-Mode", "cors")
  75. req.Header.Set("Sec-Fetch-Site", "same-origin")
  76. req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.43")
  77. req.Header.Set("X-Requested-With", "XMLHttpRequest")
  78. req.Header.Set("sec-ch-ua", `"Not.A/Brand";v="8", "Chromium";v="114", "Microsoft Edge";v="114"`)
  79. req.Header.Set("sec-ch-ua-mobile", "?0")
  80. req.Header.Set("sec-ch-ua-platform", `"Windows"`)
  81. resp, err := client.Do(req)
  82. if err != nil {
  83. log.Fatal(err)
  84. }
  85. defer resp.Body.Close()
  86. bodyText, err := io.ReadAll(resp.Body)
  87. if err != nil {
  88. log.Fatal(err)
  89. }
  90. if resp.StatusCode != 200 {
  91. log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))
  92. }
  93. var dictResponse DictResponseBD
  94. err = json.Unmarshal(bodyText, &dictResponse)
  95. if err != nil {
  96. log.Fatal(err)
  97. }
  98. fmt.Println("百度翻译")
  99. for _, item := range dictResponse.Data {
  100. fmt.Println(item.V)
  101. }
  102. wg.Done()
  103. }
  104. func queryCY(word string) {
  105. client := &http.Client{}
  106. request := DictRequestCY{TransType: "en2zh", Source: word}
  107. buf, err := json.Marshal(request)
  108. if err != nil {
  109. log.Fatal(err)
  110. }
  111. var data = bytes.NewReader(buf)
  112. req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
  113. if err != nil {
  114. log.Fatal(err)
  115. }
  116. req.Header.Set("Connection", "keep-alive")
  117. req.Header.Set("DNT", "1")
  118. req.Header.Set("os-version", "")
  119. req.Header.Set("sec-ch-ua-mobile", "?0")
  120. 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")
  121. req.Header.Set("app-name", "xy")
  122. req.Header.Set("Content-Type", "application/json;charset=UTF-8")
  123. req.Header.Set("Accept", "application/json, text/plain, */*")
  124. req.Header.Set("device-id", "")
  125. req.Header.Set("os-type", "web")
  126. req.Header.Set("X-Authorization", "token:qgemv4jr1y38jyq6vhvi")
  127. req.Header.Set("Origin", "https://fanyi.caiyunapp.com")
  128. req.Header.Set("Sec-Fetch-Site", "cross-site")
  129. req.Header.Set("Sec-Fetch-Mode", "cors")
  130. req.Header.Set("Sec-Fetch-Dest", "empty")
  131. req.Header.Set("Referer", "https://fanyi.caiyunapp.com/")
  132. req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
  133. req.Header.Set("Cookie", "_ym_uid=16456948721020430059; _ym_d=1645694872")
  134. resp, err := client.Do(req)
  135. if err != nil {
  136. log.Fatal(err)
  137. }
  138. defer resp.Body.Close()
  139. bodyText, err := io.ReadAll(resp.Body)
  140. if err != nil {
  141. log.Fatal(err)
  142. }
  143. if resp.StatusCode != 200 {
  144. log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))
  145. }
  146. var dictResponse DictResponseCY
  147. err = json.Unmarshal(bodyText, &dictResponse)
  148. if err != nil {
  149. log.Fatal(err)
  150. }
  151. fmt.Println("彩云翻译")
  152. fmt.Println(word, "UK:", dictResponse.Dictionary.Prons.En, "US:", dictResponse.Dictionary.Prons.EnUs)
  153. for _, item := range dictResponse.Dictionary.Explanations {
  154. fmt.Println(item)
  155. }
  156. wg.Done()
  157. }
  158. func main() {
  159. fmt.Println("请输入要查询的内容:")
  160. reader := bufio.NewReader(os.Stdin)
  161. word, _ := reader.ReadString('\n')
  162. word = strings.Trim(word, "\r\n")
  163. wg.Add(2)
  164. go queryCY(word)
  165. go queryBD(word)
  166. wg.Wait()
  167. }
  1. package main
  2. import (
  3. "bufio"
  4. "bytes"
  5. "encoding/json"
  6. "fmt"
  7. "io"
  8. "log"
  9. "net/http"
  10. "os"
  11. "strings"
  12. "unicode"
  13. )
  14. type DictRequestHS struct {
  15. Source string `json:"source"`
  16. Words []string `json:"words"`
  17. SourceLanguage string `json:"source_language"`
  18. TargetLanguage string `json:"target_language"`
  19. }
  20. type DictResponseHS struct {
  21. Details []struct {
  22. Detail string `json:"detail"`
  23. Extra string `json:"extra"`
  24. } `json:"details"`
  25. }
  26. type DictResponseHSData struct {
  27. Result []struct {
  28. Ec struct {
  29. Basic struct {
  30. Explains []struct {
  31. Pos string `json:"pos"`
  32. Trans string `json:"trans"`
  33. } `json:"explains"`
  34. } `json:"basic"`
  35. } `json:"ec"`
  36. } `json:"result"`
  37. }
  38. func query() {
  39. for {
  40. fmt.Println("请输入要查询的内容:")
  41. reader := bufio.NewReader(os.Stdin)
  42. word, _ := reader.ReadString('\n')
  43. word = strings.Trim(word, "\r\n")
  44. if IsEnglishString(word) {
  45. queryHS(word)
  46. break
  47. } else {
  48. fmt.Println("请输入英语")
  49. }
  50. }
  51. }
  52. func queryHS(word string) {
  53. client := &http.Client{}
  54. request := DictRequestHS{"youdao", []string{word}, "en", "zh"}
  55. buf, err := json.Marshal(request)
  56. if err != nil {
  57. log.Fatal(err)
  58. }
  59. var data = bytes.NewReader(buf)
  60. req, err := http.NewRequest("POST", "https://translate.volcengine.com/web/dict/detail/v1/?msToken=&X-Bogus=DFSzswVOQDaibrQ3tJHN7cppgiFh&_signature=_02B4Z6wo00001g0lO6gAAIDD-FrRNX0w-.4NJT8AAOfuf7", data)
  61. if err != nil {
  62. log.Fatal(err)
  63. }
  64. req.Header.Set("authority", "translate.volcengine.com")
  65. req.Header.Set("accept", "application/json, text/plain, */*")
  66. 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")
  67. req.Header.Set("content-type", "application/json")
  68. req.Header.Set("cookie", "x-jupiter-uuid=16888064002651706; i18next=zh-CN; s_v_web_id=verify_ljtrq6kx_UW3ieIzP_8gQX_4abc_B8D8_AoHwuLysn026; ttcid=db98bce9149b4f09b905a71503d9331e36")
  69. req.Header.Set("origin", "https://translate.volcengine.com")
  70. req.Header.Set("referer", "https://translate.volcengine.com/?category=&home_language=zh&source_language=detect&target_language=zh&text=bad")
  71. req.Header.Set("sec-ch-ua", `"Not.A/Brand";v="8", "Chromium";v="114", "Microsoft Edge";v="114"`)
  72. req.Header.Set("sec-ch-ua-mobile", "?0")
  73. req.Header.Set("sec-ch-ua-platform", `"Windows"`)
  74. req.Header.Set("sec-fetch-dest", "empty")
  75. req.Header.Set("sec-fetch-mode", "cors")
  76. req.Header.Set("sec-fetch-site", "same-origin")
  77. req.Header.Set("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.43")
  78. resp, err := client.Do(req)
  79. if err != nil {
  80. log.Fatal(err)
  81. }
  82. defer resp.Body.Close()
  83. bodyText, err := io.ReadAll(resp.Body)
  84. if err != nil {
  85. log.Fatal(err)
  86. }
  87. if resp.StatusCode != 200 {
  88. log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))
  89. }
  90. var dictResponse DictResponseHS
  91. err = json.Unmarshal(bodyText, &dictResponse)
  92. if err != nil {
  93. log.Fatal(err)
  94. }
  95. fmt.Println("火山翻译")
  96. item := dictResponse.Details[0]
  97. jsonStr := item.Detail
  98. var HSData DictResponseHSData
  99. err = json.Unmarshal([]byte(jsonStr), &HSData)
  100. if err != nil {
  101. panic(err)
  102. }
  103. for _, item := range HSData.Result[0].Ec.Basic.Explains {
  104. fmt.Println(item.Pos, item.Trans)
  105. }
  106. }
  107. func IsEnglishString(s string) bool {
  108. for _, r := range s {
  109. if unicode.IsLetter(r) && !unicode.Is(unicode.Scripts["Han"], r) {
  110. continue
  111. } else {
  112. return false
  113. }
  114. }
  115. return true
  116. }
  117. func main() {
  118. defer func() {
  119. if msg := recover(); msg != nil {
  120. fmt.Println(msg, "输入不合法,请重新输入")
  121. }
  122. }()
  123. query()
  124. }

火山翻译

三.SOCKS5 代理介绍

socks5是网络传输协议的一种,位于表示层与传输层之间,主要用于客户端与外网服务器之间通讯的中间传递。它是一种通用代理服务器,可以允许有权限的用户穿过防火墙的限制,使得高权限用户可以访问外部资源。大量网络应用程序都支持socks5代理。

原理:

Socks5是一种网络传输协议,位于OSI模型中的表示层与传输层之间,主要用于客户端与外网服务器之间通讯的中间传递。Socks5协议的工作原理包括以下步骤:
客户端向代理服务器发出请求信息,用于协商版本和认证方法。
代理服务器应答,将选择的方法发送给客户端。
客户端和代理服务器进入由选定认证方法所决定的子协商过程。
子协商过程结束后,客户端发送请求信息,其中包含目标服务器的IP地址和端口。
代理服务器验证客户端身份,通过后与目标服务器连接,目标服务器经过代理服务器向客户端返回状态响应。
连接完成后,代理服务器开始作为中转站中转数据。

SOCKS5代理- Tcp echo server

  1. package main
  2. import (
  3. "io"
  4. "log"
  5. "net"
  6. "time"
  7. )
  8. func main() {
  9. // 设置代理服务器配置
  10. socks.SetDefaultProxy(socks.SOCKS5, "localhost", 1080)
  11. // 创建TCP服务器套接字
  12. serverSocket, err := net.Listen("tcp", "localhost:12345")
  13. if err != nil {
  14. log.Fatal("Failed to create server socket:", err)
  15. }
  16. // 监听客户端连接
  17. go func() {
  18. for {
  19. conn, err := serverSocket.Accept()
  20. if err != nil {
  21. log.Println("Failed to accept client connection:", err)
  22. continue
  23. }
  24. log.Println("New client connected")
  25. // 设置客户端套接字为非阻塞模式
  26. conn.SetDeadline(time.Now().Add(time.Hour))
  27. // 建立到目标服务器的连接
  28. target, err := socks.Dial(conn, "localhost", 1080)
  29. if err != nil {
  30. log.Println("Failed to establish connection to target server:", err)
  31. continue
  32. }
  33. // 将客户端数据转发到目标服务器,并将目标服务器的响应回显给客户端
  34. buf := make([]byte, 1024)
  35. for {
  36. n, err := conn.Read(buf)
  37. if err != nil && err != io.EOF {
  38. log.Println("Failed to read data from client:", err)
  39. break
  40. }
  41. if n == 0 {
  42. break
  43. }
  44. target.Write(buf[:n])
  45. }
  46. target.Close()
  47. conn.Close()
  48. }
  49. }()
  50. select {} // 阻塞程序,使其不会退出
  51. }

该代码创建了一个基于Go语言的SOCKS5代理TCP回显服务器,它监听本地端口12345上的连接,并接受客户端请求。一旦客户端连接成功,服务器将通过SOCKS5代理建立到目标服务器的TCP连接,并将客户端发送的所有数据直接发送回客户端。当客户端关闭连接时,服务器将关闭相应的连接。
请注意,该代码中的代理服务器配置使用了默认的localhost地址和端口1080。如果您使用的是不同的代理服务器,请相应地更改这些值。此外,该代码中的套接字使用了非阻塞模式,这使得服务器可以处理多个客户端并发连接。

SOCKS5代理-请求阶段

SOCKS5代理是一种网络协议,用于在客户端和服务器之间建立一个代理连接。其请求阶段是SOCKS5代理通信中的重要阶段之一,主要包括以下步骤:
客户端发送SOCKS5命令:客户端首先向代理服务器发送一个SOCKS5命令,告诉代理服务器其要连接的目标服务器地址和端口号。
代理服务器进行身份验证:代理服务器收到客户端的SOCKS5命令后,会对客户端进行身份验证。如果客户端身份验证不通过,则代理服务器会拒绝建立连接。
代理服务器向目标服务器发送SOCKS5请求:如果客户端身份验证通过,则代理服务器会向目标服务器发送一个SOCKS5请求,告诉目标服务器其要连接的客户端地址和端口号。
目标服务器返回响应:目标服务器收到代理服务器的SOCKS5请求后,会向代理服务器返回一个响应,告诉代理服务器是否允许建立连接。
代理服务器将响应发送给客户端:代理服务器收到目标服务器的响应后,会将其发送给客户端,告诉客户端是否成功建立连接。
在请求阶段中,需要注意以下几点:
客户端必须支持SOCKS5协议,否则无法与代理服务器进行通信。
代理服务器需要对客户端进行身份验证,以防止恶意用户利用代理服务器进行攻击。
代理服务器需要将客户端的真实地址和端口号告诉目标服务器,以便目标服务器能够正确地与客户端进行通信。
目标服务器需要对代理服务器的SOCKS5请求进行响应,以告诉代理服务器是否允许建立连接。
总之,请求阶段是SOCKS5代理通信中非常重要的一步,需要仔细处理。

其中需要使用插件:

完整代码

  1. package main
  2. import (
  3. "bufio"
  4. "context"
  5. "encoding/binary"
  6. "errors"
  7. "fmt"
  8. "io"
  9. "log"
  10. "net"
  11. )
  12. const socks5Ver = 0x05
  13. const cmdBind = 0x01
  14. const atypIPV4 = 0x01
  15. const atypeHOST = 0x03
  16. const atypeIPV6 = 0x04
  17. func main() {
  18. server, err := net.Listen("tcp", "127.0.0.1:1080")
  19. if err != nil {
  20. panic(err)
  21. }
  22. for {
  23. client, err := server.Accept()
  24. if err != nil {
  25. log.Printf("Accept failed %v", err)
  26. continue
  27. }
  28. go process(client)
  29. }
  30. }
  31. func process(conn net.Conn) {
  32. defer conn.Close()
  33. reader := bufio.NewReader(conn)
  34. err := auth(reader, conn)
  35. if err != nil {
  36. log.Printf("client %v auth failed:%v", conn.RemoteAddr(), err)
  37. return
  38. }
  39. err = connect(reader, conn)
  40. if err != nil {
  41. log.Printf("client %v auth failed:%v", conn.RemoteAddr(), err)
  42. return
  43. }
  44. }
  45. func auth(reader *bufio.Reader, conn net.Conn) (err error) {
  46. // +----+----------+----------+
  47. // |VER | NMETHODS | METHODS |
  48. // +----+----------+----------+
  49. // | 1 | 1 | 1 to 255 |
  50. // +----+----------+----------+
  51. // VER: 协议版本,socks5为0x05
  52. // NMETHODS: 支持认证的方法数量
  53. // METHODS: 对应NMETHODS,NMETHODS的值为多少,METHODS就有多少个字节。RFC预定义了一些值的含义,内容如下:
  54. // X’00’ NO AUTHENTICATION REQUIRED
  55. // X’02’ USERNAME/PASSWORD
  56. ver, err := reader.ReadByte()
  57. if err != nil {
  58. return fmt.Errorf("read ver failed:%w", err)
  59. }
  60. if ver != socks5Ver {
  61. return fmt.Errorf("not supported ver:%v", ver)
  62. }
  63. methodSize, err := reader.ReadByte()
  64. if err != nil {
  65. return fmt.Errorf("read methodSize failed:%w", err)
  66. }
  67. method := make([]byte, methodSize)
  68. _, err = io.ReadFull(reader, method)
  69. if err != nil {
  70. return fmt.Errorf("read method failed:%w", err)
  71. }
  72. // +----+--------+
  73. // |VER | METHOD |
  74. // +----+--------+
  75. // | 1 | 1 |
  76. // +----+--------+
  77. _, err = conn.Write([]byte{socks5Ver, 0x00})
  78. if err != nil {
  79. return fmt.Errorf("write failed:%w", err)
  80. }
  81. return nil
  82. }
  83. func connect(reader *bufio.Reader, conn net.Conn) (err error) {
  84. // +----+-----+-------+------+----------+----------+
  85. // |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
  86. // +----+-----+-------+------+----------+----------+
  87. // | 1 | 1 | X'00' | 1 | Variable | 2 |
  88. // +----+-----+-------+------+----------+----------+
  89. // VER 版本号,socks5的值为0x05
  90. // CMD 0x01表示CONNECT请求
  91. // RSV 保留字段,值为0x00
  92. // ATYP 目标地址类型,DST.ADDR的数据对应这个字段的类型。
  93. // 0x01表示IPv4地址,DST.ADDR为4个字节
  94. // 0x03表示域名,DST.ADDR是一个可变长度的域名
  95. // DST.ADDR 一个可变长度的值
  96. // DST.PORT 目标端口,固定2个字节
  97. buf := make([]byte, 4)
  98. _, err = io.ReadFull(reader, buf)
  99. if err != nil {
  100. return fmt.Errorf("read header failed:%w", err)
  101. }
  102. ver, cmd, atyp := buf[0], buf[1], buf[3]
  103. if ver != socks5Ver {
  104. return fmt.Errorf("not supported ver:%v", ver)
  105. }
  106. if cmd != cmdBind {
  107. return fmt.Errorf("not supported cmd:%v", ver)
  108. }
  109. addr := ""
  110. switch atyp {
  111. case atypIPV4:
  112. _, err = io.ReadFull(reader, buf)
  113. if err != nil {
  114. return fmt.Errorf("read atyp failed:%w", err)
  115. }
  116. addr = fmt.Sprintf("%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3])
  117. case atypeHOST:
  118. hostSize, err := reader.ReadByte()
  119. if err != nil {
  120. return fmt.Errorf("read hostSize failed:%w", err)
  121. }
  122. host := make([]byte, hostSize)
  123. _, err = io.ReadFull(reader, host)
  124. if err != nil {
  125. return fmt.Errorf("read host failed:%w", err)
  126. }
  127. addr = string(host)
  128. case atypeIPV6:
  129. return errors.New("IPv6: no supported yet")
  130. default:
  131. return errors.New("invalid atyp")
  132. }
  133. _, err = io.ReadFull(reader, buf[:2])
  134. if err != nil {
  135. return fmt.Errorf("read port failed:%w", err)
  136. }
  137. port := binary.BigEndian.Uint16(buf[:2])
  138. dest, err := net.Dial("tcp", fmt.Sprintf("%v:%v", addr, port))
  139. if err != nil {
  140. return fmt.Errorf("dial dst failed:%w", err)
  141. }
  142. defer dest.Close()
  143. log.Println("dial", addr, port)
  144. // +----+-----+-------+------+----------+----------+
  145. // |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
  146. // +----+-----+-------+------+----------+----------+
  147. // | 1 | 1 | X'00' | 1 | Variable | 2 |
  148. // +----+-----+-------+------+----------+----------+
  149. // VER socks版本,这里为0x05
  150. // REP Relay field,内容取值如下 X’00’ succeeded
  151. // RSV 保留字段
  152. // ATYPE 地址类型
  153. // BND.ADDR 服务绑定的地址
  154. // BND.PORT 服务绑定的端口DST.PORT
  155. _, err = conn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0})
  156. if err != nil {
  157. return fmt.Errorf("write failed: %w", err)
  158. }
  159. ctx, cancel := context.WithCancel(context.Background())
  160. defer cancel()
  161. go func() {
  162. _, _ = io.Copy(dest, reader)
  163. cancel()
  164. }()
  165. go func() {
  166. _, _ = io.Copy(conn, dest)
  167. cancel()
  168. }()
  169. <-ctx.Done()
  170. return nil
  171. }

将这段代码在goland上运行,并在终端中输入curl --socks5 127.0.0.1 1080 -v http://www.baidu.com以测试:

 在浏览器上测试我们的SOCKS5服务器。


​​​​​​​

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小桥流水78/article/detail/992413
推荐阅读
相关标签
  

闽ICP备14008679号