Restful Web Services With Go (2)
文章目录
配置开发环境
Go 环境配置很简单,只需要安装Go编译器,设置好GOROOT 以及 GOPATH 环境变量。
网上有很多安装配置教程,这里就不多赘述了。
理解GOPATH
GOPATH用于指定golang的工作目录,告诉编译器你的源代码,二制进文件以及第三方包的存放位置。
Python程序员可能对 Virtualenv 这个工具比较熟悉,它可以同时创建多个项目(每个项目拥有不同版本的python解释器),当你想要编辑某个项目,只需要激活当前项目对应的python环境即可。
同样的道理,你也可以创建任意多个Go工作目录,当开发的时候,只需要把GOPATH设定到你的工作目录即可。
假设在家目录下创建一个目录,设置GOPATH到这里:
|
|
如果我们这是时候安装一个第三方包
|
|
Go会把项目mux从github复制一份到workspace目录下面
GOPATH下面基本的目录结构有:
- bin: 存储项目的二进制文件,这里编译好的二进制可以直接运行。
- pkg: 包含项目的包信息,提供需要编译程序所需包的各种方法。
- src: 存放用户源代码。
练手项目
注意:这里推荐使用Go modules 来开发,而不是之前的$GOPATH方法,下面的项目仅作为演示路径,请根据情况自行调整。对Go modules不熟悉的可以查看这个文件,Go modules
需求:
创建一个REST服务,从OS网站镜像列表中选取最快的下载链接返回给用户。以Debian系统为例子,网址在:https://www.debian.org/mirror/list
设计:
API返回结果是最快镜像的URL,API设计文档如下:
HTTP Verb | PATH | Action | Resource |
---|---|---|---|
GET | /fastest-mirror | fetch | URL: string |
实现:
-
假设GOPATH在/home/user/workspace,项目目录为mirrorFinder,git-user为你自己的github用户名:
1
mkdir -p $GOPATH/src/github.com/git-user/mirrorFinder
-
创建主文件main.go:
1
touch $GOPATH/src/github.com/git-user/mirrorFinder/main.go
-
创建一个目录存放镜像数据,以及data.go文件
1 2
mkdir $GOPATH/src/github.com/git-user/mirrors touch $GOPATH/src/github.com/git-user/mirrors/data.go
-
data.go中存放镜像列表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
package mirrors // MirrorList is list of Debian mirror sites var MirrorList = []string{ "http://ftp.am.debian.org/debian/", "http://ftp.au.debian.org/debian/", "http://ftp.at.debian.org/debian/", "http://ftp.by.debian.org/debian/", "http://ftp.be.debian.org/debian/", "http://ftp.br.debian.org/debian/", "http://ftp.bg.debian.org/debian/", "http://ftp.ca.debian.org/debian/", "http://ftp.cl.debian.org/debian/", "http://ftp2.cn.debian.org/debian/", "http://ftp.cn.debian.org/debian/", "http://ftp.hr.debian.org/debian/", "http://ftp.cz.debian.org/debian/", "http://ftp.dk.debian.org/debian/", "http://ftp.sv.debian.org/debian/", "http://ftp.ee.debian.org/debian/", "http://ftp.fr.debian.org/debian/", "http://ftp2.de.debian.org/debian/", "http://ftp.de.debian.org/debian/", "http://ftp.gr.debian.org/debian/", "http://ftp.hk.debian.org/debian/", "http://ftp.hu.debian.org/debian/", "http://ftp.is.debian.org/debian/", "http://ftp.it.debian.org/debian/", "http://ftp.jp.debian.org/debian/", "http://ftp.kr.debian.org/debian/", "http://ftp.lt.debian.org/debian/", "http://ftp.mx.debian.org/debian/", "http://ftp.md.debian.org/debian/", "http://ftp.nl.debian.org/debian/", "http://ftp.nc.debian.org/debian/", "http://ftp.nz.debian.org/debian/", "http://ftp.no.debian.org/debian/", "http://ftp.pl.debian.org/debian/", "http://ftp.pt.debian.org/debian/", "http://ftp.ro.debian.org/debian/", "http://ftp.ru.debian.org/debian/", "http://ftp.sg.debian.org/debian/", "http://ftp.sk.debian.org/debian/", "http://ftp.si.debian.org/debian/", "http://ftp.es.debian.org/debian/", "http://ftp.fi.debian.org/debian/", "http://ftp.se.debian.org/debian/", "http://ftp.ch.debian.org/debian/", "http://ftp.tw.debian.org/debian/", "http://ftp.tr.debian.org/debian/", "http://ftp.uk.debian.org/debian/", "http://ftp.us.debian.org/debian/", }
-
编辑main.go文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
package main import ( "encoding/json" "fmt" "log" "net/http" "time" "github.com/git-user/mirrors" ) type response struct { FastestURL string `json:"fastest_url"` Latency time.Duration `json:"latency"` } func main() { http.HandleFunc("/fastest-mirror", func(w http.ResponseWriter, r *http.Request) { response := findFastest(mirrors.MirrorList) respJSON, _ := json.Marshal(response) w.Header().Set("Content-Type", "application/json") w.Write(respJSON) }) port := ":8000" server := &http.Server{ Addr: port, ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, MaxHeaderBytes: 1 << 20, } fmt.Printf("Starting server on port %s\n", port) log.Fatal(server.ListenAndServe()) }
main函数通过net/http包创建了一个视图函数并启动HTTP服务,结构体response有两个字段:
- Fastest_url: 最快镜像的地址
- Latency: 本地请求README网页所花费的时间
-
接下来实现findFastest函数,用于从镜像列表获取最快镜像。这里用到了Go routines,当并发请求这些URL;而在函数里面还用到了两个channle,用于接收返回的信息。这里比较巧妙的设计就是,当两个channel一旦接收到数据,函数会立刻返回response响应,这样其他没有完成的Go routines会被取消,最后得到的结果就是响应最快的镜像地址。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
func findFastest(urls []string) response { urlChan := make(chan string) latencyChan := make(chan time.Duration) for _, url := range urls { mirrorURL := url go func() { start := time.Now() _, err := http.Get(mirrorURL + "/README") latency := time.Now().Sub(start) / time.Millisecond if err == nil { urlChan <- mirrorURL latencyChan <- latency } }() } return response{<-urlChan, <-latencyChan} }
-
现在使用install命令来编译:
1
go install github.com/git-user/mirrorFinder
这一步做了两件事:
- 编译mirrors包将编译后的结果放到$GOPATH/pkg 目录
- 将编译好的二进制放到$GOPATH/bin目录
-
运行程序
1
$GOPATH/bin/mirrorFinder
这时候这个API服务就启动并监听在http://localhost:8000这个端口上。
-
利用curl工具请求这个API
1
curl -i -X GET "http://localhost:8000/fastest-mirror"
响应结果为
1 2 3 4 5 6
HTTP/1.1 200 OK Content-Type: application/json Date: Thu, 05 Mar 2020 06:05:58 GMT Content-Length: 64 {"fastest_url":"http://ftp.kr.debian.org/debian/","latency":174}
使用 Swagger UI 生成API说明文档
使用Swagger UI最方便的方式是直接利用Docker启动,在这之前还需要准备一个JSON格式的配置文件,比如我们的服务需要的配置,openapi.json :
|
|
该配置文件三个部分的作用:
- info: API服务相关的描述
- servers: 配置API服务所在的地址
- paths: 这部分包含服务器提供的所有API接口描述,包括请求体,响应类型,内容结构等。
开始通过Docker安装并使用Swagger UI :
-
安装命令:
1
docker pull swaggerapi/swagger-ui
-
通过刚才的配置文件启动镜像
1
docker run --rm -p 80:8080 -e SWAGGER_JSON=/app/openapi.json -v $GOPATH/src/github.com/git-user/:/app swaggerapi/swagger-ui
通过http://127.0.0.1就可以访问这个API文档了