7.4 Request

http.request的三个属性Form、PostForm、MultipartForm:

  • Form:存储了post、put和get参数,在使用之前需要调用ParseForm方法。
  • PostForm:存储了post、put参数,在使用之前需要调用ParseForm方法。
  • MultipartForm:存储了包含了文件上传的表单的post参数,在使用前需要调用ParseMultipartForm方法。

获取Get参数

示例

  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. "net/http"
  6. )
  7. func sayHelloHandler(w http.ResponseWriter, r *http.Request) {
  8. r.ParseForm()//解析url传递的参数,对于POST则解析响应包的主体(request body)
  9. //注意:如果没有调用ParseForm方法,下面无法获取表单的数据
  10. uid := r.Form["uid"]
  11. fmt.Println(uid)
  12. }
  13. func main() {
  14. http.HandleFunc("/", sayHelloHandler) // 设置访问路由
  15. log.Fatal(http.ListenAndServe(":8080", nil))
  16. }

用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参数怎么办?可以改进代码:

  1. query := r.URL.Query()
  2. uid := query["uid"][0]
  3. fmt.Println(uid)

以上代码意思是获取Url问号后地代码。

application/json

针对content-type类型是application/json的格式的数据,也可以通过以下方式获取。

  1. body, _ := ioutil.ReadAll(r.Body)
  2. fmt.Println(string(body))
  3. var data map[string]interface{}
  4. err := json.Unmarshal(body, &data)
  5. if err != nil {
  6. fmt.Println(err)
  7. }
  8. fmt.Println(data)

获取POST参数

这里有两种情况:

  • 普通的post表单请求,Content-Type=application/x-www-form-urlencoded
  • 有文件上传的表单,Content-Type=multipart/form-data

第一种情况,只获取文本类型参数用以下代码:

  1. uid := r.PostFormValue("uid")
  2. fmt.Println(uid)

  1. r.ParseForm()
  2. uid := r.PostForm["uid"]
  3. fmt.Println(uid)

r.PostFormValue()和r.PostForm区别是r.PostFormValue()只获取第一个参数,r.PostForm获取的是一个数组。

第二种情况,获取文本类型参数用以下代码:

  1. r.ParseMultipartForm(32 << 20)
  2. if r.MultipartForm != nil {
  3. values := r.MultipartForm.Value["uid"]
  4. fmt.Println(values)
  5. }

application/json

针对content-type类型是application/json的格式的数据,可以通过以下方式实现。

  1. body, _ := ioutil.ReadAll(r.Body)
  2. fmt.Println(string(body))
  3. var data map[string]interface{}
  4. err := json.Unmarshal(body, &data)
  5. if err != nil {
  6. fmt.Println(err)
  7. }
  8. fmt.Println(data)

可以看到post和get的获取json数据的方式是一样的,这里也要注意一点post请求下,ioutil.ReadAll(r.Body) 不能和r.ParseForm()一起使用。

获取header信息

  1. if len(r.Header) > 0 {
  2. for k,v := range r.Header {
  3. fmt.Printf("%s=%s\n", k, v[0])
  4. }
  5. }

获取ip

  1. func GetRemoteIp(req *http.Request) string {
  2. remoteAddr := req.RemoteAddr
  3. if ip := req.Header.Get("X-Real-IP"); ip != "" {
  4. remoteAddr = ip
  5. } else if ip = req.Header.Get("X-Forwarded-For"); ip != "" {
  6. remoteAddr = ip
  7. } else {
  8. remoteAddr, _, _ = net.SplitHostPort(remoteAddr)
  9. }
  10. if remoteAddr == "::1" {
  11. remoteAddr = "127.0.0.1"
  12. }
  13. return remoteAddr
  14. }

处理上传单个文件

  1. package main
  2. import (
  3. "log"
  4. "net/http"
  5. "os"
  6. "io"
  7. )
  8. func sayHelloHandler(w http.ResponseWriter, r *http.Request) {
  9. // 根据字段名获取表单文件
  10. formFile, header, err := r.FormFile("uploadfile")
  11. if err != nil {
  12. log.Printf("Get form file failed: %s\n", err)
  13. return
  14. }
  15. defer formFile.Close()
  16. // 创建保存文件
  17. destFile, err := os.Create("./upload/" + header.Filename)
  18. if err != nil {
  19. log.Printf("Create failed: %s\n", err)
  20. return
  21. }
  22. defer destFile.Close()
  23. // 读取表单文件,写入保存文件
  24. _, err = io.Copy(destFile, formFile)
  25. if err != nil {
  26. log.Printf("Write file failed: %s\n", err)
  27. return
  28. }
  29. //fmt.Fprintf(w, "Hello world!\n") //这个写入到w的是输出到客户端的
  30. }
  31. func main() {
  32. http.HandleFunc("/", sayHelloHandler) // 设置访问路由
  33. log.Fatal(http.ListenAndServe(":8080", nil))
  34. }

处理上传多个文件

  1. package main
  2. import (
  3. "fmt"
  4. "io"
  5. "log"
  6. "net/http"
  7. "os"
  8. )
  9. func sayHelloHandler(w http.ResponseWriter, r *http.Request) {
  10. //设置内存大小
  11. r.ParseMultipartForm(32 << 20)
  12. //获取上传的文件组
  13. files := r.MultipartForm.File["uploadfile"]
  14. len := len(files)
  15. for i := 0; i < len; i++ {
  16. //打开上传文件
  17. file, err := files[i].Open()
  18. defer file.Close()
  19. if err != nil {
  20. log.Fatal(err)
  21. }
  22. //创建上传目录
  23. os.Mkdir("./upload", os.ModePerm)
  24. //创建上传文件
  25. cur, err := os.Create("./upload/" + files[i].Filename)
  26. defer cur.Close()
  27. if err != nil {
  28. log.Fatal(err)
  29. }
  30. io.Copy(cur, file)
  31. fmt.Println(files[i].Filename) //输出上传的文件名
  32. }
  33. //fmt.Fprintf(w, "Hello world!\n") //这个写入到w的是输出到客户端的
  34. }
  35. func main() {
  36. http.HandleFunc("/", sayHelloHandler) // 设置访问路由
  37. log.Fatal(http.ListenAndServe(":8080", nil))
  38. }

links