前言
填坑…
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))
响应主体还是使用模板比较好一点啊。
Cookie
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
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!