前言

开个go的坑,填坑时间不定。


环境搭建

系统:docker+Ubuntu18.04镜像

安装golang:

apt-get update
apt-get install golang

在Ubuntu18.04下即可安装1.10版本的golang,如果需要最新版本的可以去https://golang.org/dl/(需要翻墙),或者直接wget下载,然后解压、建立工作目录并配置环境变量:

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一下即可看到:

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版本:

go version go1.12.1 linux/amd64

安装完成。


Hello World && Go Web 服务器

在GOPATH/src下新建一个目录hello_word,然后新建go源代码文件,代码如下:

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字符串中作为响应,我们编译运行:

go install hello_world
$GOPATH/bin/hello_world

浏览器打开即可看到效果。


多路复用 && 更多的Server配置

我们还可以通过Server结构体对服务器进行更多的配置,写法如下:

server := http.Server {
    Addr: "0.0.0.0:80",
}
server.ListenAndServe()

Server结构的配置选项如下:

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来根据请求地址分发请求到不同的处理器。


处理器 && 处理器函数

处理器:

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")
}

路由配置:

index := IndexHandler{}
login := LoginHandler{}
http.Handle("/index", &index)
http.Handle("/login", &login)

处理器函数:

func index(writer http.ResponseWriter, request *http.Request) {
    fmt.Fprintf(writer, "Index")
}
func login(writer http.ResponseWriter, request *http.Request) {
    fmt.Fprintf(writer, "Login")
}

路由配置:

http.HandleFunc("/index", index)
http.HandleFunc("/login", login)

处理器是一个拥有ServeHTTP方法的接口,它被用来处理HTTP请求,而处理器函数则是与处理器拥有相同行为的函数,也是用来创建处理器的一种便利的方法,当我们调用HandlerFunc函数来注册路由的时候,HandlerFunc就会将处理器函数转换成处理器,然后将它与DefaultServeMux进行绑定。

串联处理器函数:

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函数代码之后再继续执行它的感觉,跟一般的函数调用不太一样。

串联处理器跟串联处理器函数十分相似,只要修改一下类型就好了:

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,一个高效的轻量级第三方多路复用器,安装:

apt-get install git
go get github.com/julienschmidt/httprouter

Go会使用git从GitHub上下载源代码,然后储存到$GOPATH/src目录下,我们还需要把它从github.com文件夹中取出来:

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


Web Go

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!

SVG XSS-CDN-Web缓存投毒
自动绑定漏洞+war远程调试