这是我参与「第三届青训营 -后端场」笔记创作活动的的第1篇笔记。
课程内容分为两部分,Go语言基础和三个项目实例。本篇笔记主要讲述后面的三个项目。
开发环境使用windows10/11 + WSL2, go编辑器为 VSCode + go 插件。vscode可以使用remote-wsl插件连接WSL。
猜谜游戏
这是一个很基础的Go项目,主要考察GO的输入输出,错误判断。
随机数
为了生成真随机数,需要设置随机种子,通常使用当前时间作为种子。
maxNum := 100
rand.Seed(time.Now().UnixNano())
secretNumber := rand.Intn(maxNum)
错误处理
关于go的错误处理,最典型的如下
input, err := reader.ReadString('\n')
if err != nil {
fmt.Println("An error occured while reading input. Please try again", err)
}
这种处理错误的方式,隐含go的设计思想,希望程序员能对每个错误在哪处理,怎么处理进行清晰的设计。缺点是比较繁琐,在大型项目中不一定合适。
go的其它错误处理的设计方法,见Go工程化实践 - 1.三种常见的错误处理方式_哔哩哔哩_bilibili
输入输出
go的fmt包里实现了类似C语言printf和scanf的格式化I/O,详细参阅(Go语言标准库文档中文版 | Go语言中文网 | Golang中文社区 | Golang中国 (studygolang.com))
而在项目中,使用了另一种更常规的输入输出方法(可能不是很方便,所以课后作业要求更改为fmt方式)
reader := bufio.NewReader(os.Stdin)
input, err := reader.ReadString('\n')//读到换行为止,注意windows和linux表达换行语义的符号有点区别
简易字典
字典搜索引擎是由第三方提供的,本项目只是设计了一个web服务,用于向这个第三方发送搜索请求,得到返回结果后筛选并展示。
如何构造一个HTTP请求
正常构造HTTP请求的方式是确定好目标地址,请求方法,payload,以及设置header
req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
req.Header.Set("Connection", "keep-alive")
req.Header.Set("DNT", "1")
req.Header.Set("os-version", "")
...
但是在这个项目中,一个简便的方式是:
- 打开“彩云翻译”在线翻译的页面
- F12打开开发者模式
- 输入“good”,点击翻译
- 找到“网络”中的dict包,将其复制为cURLs格式
- 打开Convert curl commands to code (curlconverter.com)进行翻译
如何使用JSON
网络传输中,一般需要使用一种序列化标准,把对象数据序列化为字符串并进行传输,在另一端进行反序列化得到数据对象。本项目使用JSON来实现
如何快速地构造一个JSON地结构体呢?使用这个网站JSON转Golang Struct - 在线工具 - OKTools
只要在里面复制一段JSON字符串,就能得到对应地结构体定义。JSON字符串格式可以在浏览器开发者模式中观察请求的负载和响应的负载得到。
关于encoding/json包的使用,可自行查阅其它资料。
代理服务器
这个项目使用SOCKS5协议实现转发代理服务器
如何建立web服务
一个基于tcp的web服务端的基础逻辑(监听并建立连接)代码如下:
server, err := net.Listen("tcp", "127.0.0.1:1080")
if err != nil {
panic(err)
}
for {
client, err := server.Accept()
if err != nil {
log.Printf("Accept failed %v", err)
continue
}
go process(client)
}
那么对于一个tcp连接,如何处理请求,项目中定义处理函数为process,每一个连接会启动一个go协程进行处理,处理内容包括接收数据,分析处理,返回数据。(进阶知识:IO多路复用)