前言
开个go的坑,填坑时间不定。
环境搭建
系统:docker+Ubuntu18.04镜像
安装golang:
1 2
| apt-get update apt-get install golang
|
在Ubuntu18.04下即可安装1.10版本的golang,如果需要最新版本的可以去https://golang.org/dl/(需要翻墙),或者直接wget下载,然后解压、建立工作目录并配置环境变量:
1 2 3 4 5 6 7 8 9 10
| cd /opt wget https://dl.google.com/go/go1.12.1.linux-amd64.tar.gz tar zxvf go1.12.1.linux-amd64.tar.gz cd mkdir -p golang/src golang/bin echo "export GOROOT=/opt/go" >> .bashrc echo "export GOPATH=/root/golang" >> .bashrc source .bashrc echo "export PATH=$GOPATH/bin:$GOROOT/bin:$PATH" >> .bashrc source .bashrc
|
然后export一下即可看到:
1 2 3
| declare -x GOPATH="/root/golang" declare -x GOROOT="/opt/go" declare -x PATH="/root/golang/bin:/opt/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
最后运行go version,看到golang版本:
1
| go version go1.12.1 linux/amd64
|
安装完成。
Hello World && Go Web 服务器
在GOPATH/src下新建一个目录hello_word,然后新建go源代码文件,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package main
import ( "fmt" "net/http" )
func handler(writer http.ResponseWriter, request *http.Request) { fmt.Fprintf(writer, "Hello World, %s!", request.URL.Path[1:]) }
func main() { http.HandleFunc("/index", handler) http.ListenAndServe(":80", nil) }
|
很简单的逻辑,服务端监听80端口,然后把对/index的访问请求都交给handler来处理,而handler则获取我们的请求URL,然后格式化进Hello World字符串中作为响应,我们编译运行:
1 2
| go install hello_world $GOPATH/bin/hello_world
|
浏览器打开即可看到效果。
多路复用 && 更多的Server配置
我们还可以通过Server结构体对服务器进行更多的配置,写法如下:
1 2 3 4
| server := http.Server { Addr: "0.0.0.0:80", } server.ListenAndServe()
|
Server结构的配置选项如下:
1 2 3 4 5 6 7 8 9 10 11
| type Server struct { Addr string Handler Handler ReadTimeout time.Duration WriteTimeout time.Duration MaxHeaderBytes int TLSConfig *tls.Config TLSNextProto map[string]func(*Server, *tls.Conn, Handler) ConnState func(net.Conn, ConnStats) ErrorLog *log.Logger }
|
Handler参数的默认值为DefaultServeMux多路复用处理器,它是ServeMux结构(多路复用器)的一个实例,具备处理器的特征(ServeHTTP方法),它的作用是根据请求的URL的不同,将请求交付不同的处理器来进行处理,如果我们将它覆盖为一个普通的处理器,无论我们访问什么地址,服务器返回的响应都是相同的。利用多路复用器,我们就可以通过配置http.HandleFunc或者http.Handle来根据请求地址分发请求到不同的处理器。
处理器 && 处理器函数
处理器:
1 2 3 4 5 6 7 8
| type IndexHandler struct{} func (h *IndexHandler) ServeHTTP (writer http.ResponseWriter, request *http.Request) { fmt.Fprintf(writer, "Index") } type LoginHandler struct{} func (h *LoginHandler) ServeHTTP (writer http.ResponseWriter, request *http.Request) { fmt.Fprintf(writer, "Login") }
|
路由配置:
1 2 3 4
| index := IndexHandler{} login := LoginHandler{} http.Handle("/index", &index) http.Handle("/login", &login)
|
处理器函数:
1 2 3 4 5 6
| func index(writer http.ResponseWriter, request *http.Request) { fmt.Fprintf(writer, "Index") } func login(writer http.ResponseWriter, request *http.Request) { fmt.Fprintf(writer, "Login") }
|
路由配置:
1 2
| http.HandleFunc("/index", index) http.HandleFunc("/login", login)
|
处理器是一个拥有ServeHTTP方法的接口,它被用来处理HTTP请求,而处理器函数则是与处理器拥有相同行为的函数,也是用来创建处理器的一种便利的方法,当我们调用HandlerFunc函数来注册路由的时候,HandlerFunc就会将处理器函数转换成处理器,然后将它与DefaultServeMux进行绑定。
串联处理器函数:
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
| package main
import ( "fmt" "net/http" "reflect" "runtime" )
func index(writer http.ResponseWriter, request *http.Request) { fmt.Fprintf(writer, "Index") } func login(writer http.ResponseWriter, request *http.Request) { fmt.Fprintf(writer, "Login") }
func log(h http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { name := runtime.FuncForPC(reflect.ValueOf(h).Pointer()).Name() fmt.Println(name) h(w, r) } }
func main() { server := http.Server { Addr: "0.0.0.0:80", } http.HandleFunc("/index", log(index)) http.HandleFunc("/login", log(login)) server.ListenAndServe() }
|
runtime.FuncForPC的作用是在程序运行时获取函数信息,reflect.ValueOf的作用是获取函数的副本,Go的处理器函数调用相当于一种先hook住处理器函数index,先执行完log函数代码之后再继续执行它的感觉,跟一般的函数调用不太一样。
串联处理器跟串联处理器函数十分相似,只要修改一下类型就好了:
1 2 3 4 5
| func log(h http.Handler) http.Handler { return http.HandlerFunc (func(w http.ResponseWriter, r *http.Request) { h.ServeHTTP(w, r) }) }
|
使用第三方多路复用器
DefaultServe的缺陷在于访问/index/123之类的地址的时候,无法获取GET请求的参数。为了弥补这个缺陷,我们可以使用julienschmidt/httprouter,一个高效的轻量级第三方多路复用器,安装:
1 2
| apt-get install git go get github.com/julienschmidt/httprouter
|
Go会使用git从GitHub上下载源代码,然后储存到$GOPATH/src目录下,我们还需要把它从github.com文件夹中取出来:
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
| package main
import ( "fmt" "net/http" "julienschmidt/httprouter" )
func index(writer http.ResponseWriter, request *http.Request, p httprouter.Params) { fmt.Fprintf(writer, "Index, %s!", p.ByName("p")) } func login(writer http.ResponseWriter, request *http.Request, p httprouter.Params) { fmt.Fprintf(writer, "Login, %s!", p.ByName("id")) }
func main() { mux := httprouter.New() mux.GET("/index:p", index) mux.GET("/login/:id", login) server := http.Server { Addr: "0.0.0.0:80", Handler: mux, } server.ListenAndServe() }
|
HTTP2 && HTTPS
不整了,这个就靠反向代理。
Orz