7.4 Request
http.request的三个属性Form、PostForm、MultipartForm:
- Form:存储了post、put和get参数,在使用之前需要调用ParseForm方法。
- PostForm:存储了post、put参数,在使用之前需要调用ParseForm方法。
- MultipartForm:存储了包含了文件上传的表单的post参数,在使用前需要调用ParseMultipartForm方法。
获取Get参数
示例
package main
import (
"fmt"
"log"
"net/http"
)
func sayHelloHandler(w http.ResponseWriter, r *http.Request) {
r.ParseForm()//解析url传递的参数,对于POST则解析响应包的主体(request body)
//注意:如果没有调用ParseForm方法,下面无法获取表单的数据
uid := r.Form["uid"]
fmt.Println(uid)
}
func main() {
http.HandleFunc("/", sayHelloHandler) // 设置访问路由
log.Fatal(http.ListenAndServe(":8080", nil))
}
用postman测试,提交http://localhost:8080/?uid=111
服务端输出 :[111]
提交: http://localhost:8080/?uid=111&uid=222
服务端输出:[111 222]
小结:r.Form是url.Values字典类型,r.Form[“id”]取到的是一个数组类型。因为http.request在解析参数的时候会将同名的参数都放进同一个数组里。
因为r.Form包含了GET、POST参数,POST参数优先,那么想只获取GET参数怎么办?可以改进代码:
query := r.URL.Query()
uid := query["uid"][0]
fmt.Println(uid)
以上代码意思是获取Url问号后地代码。
application/json
针对content-type类型是application/json
的格式的数据,也可以通过以下方式获取。
body, _ := ioutil.ReadAll(r.Body)
fmt.Println(string(body))
var data map[string]interface{}
err := json.Unmarshal(body, &data)
if err != nil {
fmt.Println(err)
}
fmt.Println(data)
获取POST参数
这里有两种情况:
- 普通的post表单请求,Content-Type=application/x-www-form-urlencoded
- 有文件上传的表单,Content-Type=multipart/form-data
第一种情况,只获取文本类型参数用以下代码:
uid := r.PostFormValue("uid")
fmt.Println(uid)
或
r.ParseForm()
uid := r.PostForm["uid"]
fmt.Println(uid)
r.PostFormValue()和r.PostForm区别是r.PostFormValue()只获取第一个参数,r.PostForm获取的是一个数组。
第二种情况,获取文本类型参数用以下代码:
r.ParseMultipartForm(32 << 20)
if r.MultipartForm != nil {
values := r.MultipartForm.Value["uid"]
fmt.Println(values)
}
application/json
针对content-type类型是application/json
的格式的数据,可以通过以下方式实现。
body, _ := ioutil.ReadAll(r.Body)
fmt.Println(string(body))
var data map[string]interface{}
err := json.Unmarshal(body, &data)
if err != nil {
fmt.Println(err)
}
fmt.Println(data)
可以看到post和get的获取json数据的方式是一样的,这里也要注意一点post请求下,ioutil.ReadAll(r.Body) 不能和r.ParseForm()一起使用。
获取header信息
if len(r.Header) > 0 {
for k,v := range r.Header {
fmt.Printf("%s=%s\n", k, v[0])
}
}
获取ip
func GetRemoteIp(req *http.Request) string {
remoteAddr := req.RemoteAddr
if ip := req.Header.Get("X-Real-IP"); ip != "" {
remoteAddr = ip
} else if ip = req.Header.Get("X-Forwarded-For"); ip != "" {
remoteAddr = ip
} else {
remoteAddr, _, _ = net.SplitHostPort(remoteAddr)
}
if remoteAddr == "::1" {
remoteAddr = "127.0.0.1"
}
return remoteAddr
}
处理上传单个文件
package main
import (
"log"
"net/http"
"os"
"io"
)
func sayHelloHandler(w http.ResponseWriter, r *http.Request) {
// 根据字段名获取表单文件
formFile, header, err := r.FormFile("uploadfile")
if err != nil {
log.Printf("Get form file failed: %s\n", err)
return
}
defer formFile.Close()
// 创建保存文件
destFile, err := os.Create("./upload/" + header.Filename)
if err != nil {
log.Printf("Create failed: %s\n", err)
return
}
defer destFile.Close()
// 读取表单文件,写入保存文件
_, err = io.Copy(destFile, formFile)
if err != nil {
log.Printf("Write file failed: %s\n", err)
return
}
//fmt.Fprintf(w, "Hello world!\n") //这个写入到w的是输出到客户端的
}
func main() {
http.HandleFunc("/", sayHelloHandler) // 设置访问路由
log.Fatal(http.ListenAndServe(":8080", nil))
}
处理上传多个文件
package main
import (
"fmt"
"io"
"log"
"net/http"
"os"
)
func sayHelloHandler(w http.ResponseWriter, r *http.Request) {
//设置内存大小
r.ParseMultipartForm(32 << 20)
//获取上传的文件组
files := r.MultipartForm.File["uploadfile"]
len := len(files)
for i := 0; i < len; i++ {
//打开上传文件
file, err := files[i].Open()
defer file.Close()
if err != nil {
log.Fatal(err)
}
//创建上传目录
os.Mkdir("./upload", os.ModePerm)
//创建上传文件
cur, err := os.Create("./upload/" + files[i].Filename)
defer cur.Close()
if err != nil {
log.Fatal(err)
}
io.Copy(cur, file)
fmt.Println(files[i].Filename) //输出上传的文件名
}
//fmt.Fprintf(w, "Hello world!\n") //这个写入到w的是输出到客户端的
}
func main() {
http.HandleFunc("/", sayHelloHandler) // 设置访问路由
log.Fatal(http.ListenAndServe(":8080", nil))
}