前言

填坑…

Go 有一点比较要注意的就是大小写了。


先填一下 Go 语法的坑吧

把简单的手册读完,就这样吧,我读的是菜鸟教程 2333。


请求

请求 URL

request.URL 是个指向 url.URL 结构体的指针,而这个结构体中存放了请求 URL 相关的数据,比如 request.URL.Path。

请求头

请求头存放在 request.Header 中,遍历输出一下:

for key, value := range request.Header {
    fmt.Fprintln(writer, key, ": ", value)
}

大致就是这样:

Accept :  [text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8]
Accept-Language :  [zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3]
Accept-Encoding :  [gzip, deflate]
Cookie :  [csrftoken=J8qkz9Ebk6VDXsf4T1rkTmJ39T3uiOe0zD4j4tm9xOe5K8ATfcioJPu7sQKBGTPO]
Connection :  [keep-alive]
Upgrade-Insecure-Requests :  [1]
User-Agent :  [Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0]

可以使用 [] 或者 Get() 来取值。

请求 body

body 存放在 request.Body 中,是一个 io.ReadCloser 接口,同时包含了 reader 和 closer 接口,我们要获取 body 的内容就需要调用 Read 方法,从 Body 中读取固定长度的字节放进 make 方法创建的语言切片中:

len := request.ContentLength
body := make([]byte, len)
request.Body.Read(body)
request.Body.Close()
fmt.Fprintf(writer, string(body))

可以得到未经过处理的 body,想要获取 POST 提交的表单还有内置的方法,不需要我们自己去解析。

Form
request.ParseForm()
fmt.Fprintln(writer, request.Form["a"][0], request.Form["a"][1])
fmt.Fprintln(writer, request.Form)

这种方式不分 GET 和 POST,比如我们 GET 提交 a=456&a=0,POST 提交 a=123&b=abc&a=789,结果就是:

123 789
map[a:[123 789 456 0] b:[abc]]

它会将相同键值的合并到一起。

PostForm

如果只想要 POST 的数据,就使用 PostForm 方法:

request.ParseForm()
fmt.Fprintln(writer, request.PostForm)

结果就只剩下:

map[a:[123 789] b:[abc]]
MultipartForm

这种类型要自己写太麻烦了,所以整个简单的表单:

<form action="http://***/register?myname=Twings" method="POST" enctype="multipart/form-data">
    <input type="text" name="myname">
    <input type="file" name="myfile">
    <input type="submit">
</form>

然后:

request.ParseMultipartForm(1024)
fmt.Fprintln(writer, request.MultipartForm)

效果如下:

&{map[myname:[Aluvion]] map[myfile:[0xc00007e820]]}

MultipartForm 只会接受 POST 的数据,而且文本数据和文件会分开放在两个 map 里面。

FormValue、Form、PostFormValue、PostForm

比较方便的取值方法,会自动解析 multipart/form-data 或者 application/x-www-form-urlencoded 编码方式的表单(1.12 版本的 go 中好像可以自动解析了)使用方式类似这样:

fmt.Fprintln(writer, request.FormValue("myname"))

Form 会返回整个表单,而 FormValue 只会按顺序返回一个我们需要的键的值。

Form 会从 GET 和 POST 中取值。

感觉上来说,GET 的数据用多路复用器来获取比较好,POST 的可以用 PostFormValue。

文件上传

要引入 io/io.util 包,比较麻烦的方法,不过可以上传多个文件:

request.ParseMultipartForm(1024)
fileHeader := request.MultipartForm.File["myfile"][0]
file, err := fileHeader.Open()
if err == nil {
    data, err := ioutil.ReadAll(file)
    if err == nil {
        fmt.Fprintln(writer, string(data))
    }
}

比较简单的方法,类似 FormValue:

file, _, err := request.FormFile("myfile")
if err == nil {
    data, err := ioutil.ReadAll(file)
    if err == nil {
        fmt.Fprintln(writer, string(data))
    }
}

获取完文件还有别的操作,比如大小校验、文件类型校验、写入文件等等,这里留坑。

JSON

留个坑。

响应

ResponseWriter 接口有三种用来处理响应的方法:

  • Write 用于处理响应主体
  • WriteHeader 用于处理响应码
  • Header 用于处理响应头

如下:

html := `<html>
        <head>
            <title>Hello World!</title>
        </head>
        <body>
            <h1>Hello World!</h1>
        </body>
        </html>`
writer.Header().Set("FLAG", "flag{0123456789}")
writer.WriteHeader(233)
writer.Write([]byte(html))

响应主体还是使用模板比较好一点啊。

Go 的 Cookie 是一个结构体,要设置 Cookie 可以先设置一个 http.Cookie 结构体,然后用 Header 将 Cookie Set 到客户端:

cookie1 := http.Cookie{
    Name: "HINT1",
    Value: "FLAG is not here",
    HttpOnly: true,
}
cookie2 := http.Cookie{
    Name: "HINT2",
    Value: "FLAG in db",
    HttpOnly: true,
}
writer.Header().Set("Set-Cookie", cookie1.String())
writer.Header().Add("Set-Cookie", cookie2.String())

用 Add 可以继续第二个 Cookie,或者使用 http.SetCookie:

http.SetCookie(writer, &cookie1)
http.SetCookie(writer, &cookie2)

Go 想要获取 Cookie 也有两种方法,一种是简单粗暴的 Header[“Cookie”] / Header.Get(“Cookie”),另一种比较简单,是内置的 request.Cookie 方法,Cookies 方法获得的则是全部 Cookie,得到的是一个指向 Cookie 结构体的指针:

cookie1, err := request.Cookie("HINT1")
if err != nil {
    if err == http.ErrNoCookie {
        fmt.Fprintln(writer, "No Cookie1")
    }
} else {
    cookie2, err := request.Cookie("HINT2")
    if err != nil {
        if err == http.ErrNoCookie {
            fmt.Fprintln(writer, "No Cookie2")
        }
    } else {
        html := cookie1.Value + cookie2.Value
        writer.Write([]byte(html))
    }
}

Go 的 base64 编码,引入 encoding/base64 包,然后:

base64.URLEncoding.EncodeToString()

Orz


Web Go

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

code-break2018-picklecode+Django远程调试
Docker-官方镜像使用