一、post请求的Content-Type为键值对
1、PostForm方式
package main
import (
    "net/http"
    "net/url"
    "fmt"
    "io/ioutil"
    "bytes"
    "strings"
    "mime/multipart"
    "os"
    "io"
    "time"
)
func main() {
    postForm1()
}
//以PostForm的方式发送body为键值对的post请求
func postForm1() {
    //这是一个Post 参数会被返回的地址  `这里写代码片`
    uri:="http://127.0.0.1:8888/test"
    data := urlValues()
    resopne,err:= http.PostForm(uri,data)
    if err !=nil {
        fmt.Println("err=",err)
        }
    //http返回的response的body必须close,否则就会有内存泄露
    defer func() {
        resopne.Body.Close()
        fmt.Println("finish")
        }()
    body,err:=ioutil.ReadAll(resopne.Body)
    if err!=nil {
        fmt.Println(" post err=",err)
        }
    fmt.Println(string(body))
}
//获取键值对的body
func urlValues() url.Values{
    //方式1
    data1 := url.Values{"name":{"TiMi"},"id":{"123"}}
    fmt.Println(data1)
    //方式2
    data2 := url.Values{}
    data2.Set("name", "TiMi")
    data2.Set("id", "123")
    fmt.Println(data2)
    //方式3
    data3 := make(url.Values)
    data3["name"] = []string{"TiMi"}
    data3["id"] = []string{"123"}
    fmt.Println(data3)
    /*
        map[id:[123] name:[TiMi]]
        map[id:[123] name:[TiMi]]
        map[id:[123] name:[TiMi]]
    */
    return data1
}
 
 
2、Do方式
package main
import (
    "net/http"
    "net/url"
    "fmt"
    "io/ioutil"
    "bytes"
    "strings"
    "mime/multipart"
    "os"
    "io"
    "time"
)
func main() {
    postForm2()
}
//以Do的方式发送body为键值对的post请求
func postForm2() {
    uri := "http://127.0.0.1:8888"
    resource := "/test"
    data := urlValues()
    u, _ := url.ParseRequestURI(uri)
    u.Path = resource
    urlStr := u.String()
    client := &http.Client{}
    r, _ := http.NewRequest("POST", urlStr, strings.NewReader(data.Encode()))
    r.Header.Add("Content-Type", "application/x-www-form-urlencoded")
    res, err := client.Do(r)
    if err != nil {
        fmt.Println(err.Error())
        return
    }
    //http返回的response的body必须close,否则就会有内存泄露
    defer func() {
        res.Body.Close()
        fmt.Println("finish")
    }()
    //读取body
    body,err:=ioutil.ReadAll(res.Body)
    if err!=nil {
        fmt.Println(" post err=",err)
    }
    fmt.Println(string(body))
}
func urlValues() url.Values{
    //方式1
    data1 := url.Values{"name":{"TiMi"},"id":{"123"}}
    fmt.Println(data1)
    //方式2
    data2 := url.Values{}
    data2.Set("name", "TiMi")
    data2.Set("id", "123")
    fmt.Println(data2)
    //方式3
    data3 := make(url.Values)
    data3["name"] = []string{"TiMi"}
    data3["id"] = []string{"123"}
    fmt.Println(data3)
    /*
        map[id:[123] name:[TiMi]]
        map[id:[123] name:[TiMi]]
        map[id:[123] name:[TiMi]]
    */
    return data1
}
 
 
 
二、post请求发送文件
1、以二进制形式上传
package main
import (
    "net/http"
    "net/url"
    "fmt"
    "io/ioutil"
    "bytes"
    "strings"
    "mime/multipart"
    "os"
    "io"
    "time"
)
func main() {
    postFile1()
}
//以二进制格式上传文件
func postFile1(){
    //这是一个Post 参数会被返回的地址
    uri:="http://127.0.0.1:8888/test"
    byte,err:=ioutil.ReadFile("redis_file.zip")
    res,err :=http.Post(uri,"multipart/form-data",bytes.NewReader(byte))
    if err !=nil {
        fmt.Println("err=",err)
    }
    //http返回的response的body必须close,否则就会有内存泄露
    defer func() {
        res.Body.Close()
        fmt.Println("finish")
    }()
    //读取body
    body,err:=ioutil.ReadAll(res.Body)
    if err!=nil {
        fmt.Println(" post err=",err)
    }
    fmt.Println(string(body))
}
 
 
2、以键值对形式上传
package main
import (
    "net/http"
    "net/url"
    "fmt"
    "io/ioutil"
    "bytes"
    "strings"
    "mime/multipart"
    "os"
    "io"
    "time"
)
func main() {
    postFile2()
}
//以键值对形式上传文件
func postFile2() {
    uri := "http://127.0.0.1:8888/test"
    paramName := "file"
    filePath := "redis_file.zip"
    //打开要上传的文件
    file, err := os.Open(filePath)
    if err != nil {
        fmt.Println(" post err=",err)
    }
    defer file.Close()
    body := &bytes.Buffer{}
    //创建一个multipart类型的写文件
    writer := multipart.NewWriter(body)
    //使用给出的属性名paramName和文件名filePath创建一个新的form-data头
    part, err := writer.CreateFormFile(paramName, filePath)
    if err != nil {
        fmt.Println(" post err=",err)
    }
    //将源复制到目标,将file写入到part   是按默认的缓冲区32k循环操作的,不会将内容一次性全写入内存中,这样就能解决大文件的问题
    _, err = io.Copy(part, file)
    err = writer.Close()
    if err != nil {
        fmt.Println(" post err=",err)
    }
    request, err := http.NewRequest("POST", uri, body)
    request.Header.Add("S-COOKIE2", "a=2l=310260000000000&m=460&n=00")
    //writer.FormDataContentType() : 返回w对应的HTTP multipart请求的Content-Type的值,多以multipart/form-data起始
    request.Header.Set("Content-Type", writer.FormDataContentType())
    //设置host,只能用request.Host = “”,不能用request.Header.Add(),也不能用request.Header.Set()来添加host
    request.Host = "api.shouji.com"
    t := http.DefaultTransport.(*http.Transport).Clone()
    t.MaxIdleConns = 100
    t.MaxConnsPerHost = 100
    t.MaxIdleConnsPerHost = 100
    clt := http.Client{
        Timeout:   10 * time.Second,
        Transport: t,
    }
    defer clt.CloseIdleConnections()
    res, err := clt.Do(request)
    //http返回的response的body必须close,否则就会有内存泄露
    defer func() {
        res.Body.Close()
        fmt.Println("finish")
    }()
    if err != nil {
        fmt.Println("err is ", err)
    }
    body1, err1 := ioutil.ReadAll(res.Body)
    if err != nil {
        fmt.Println("ioutil.ReadAll  err is ", err1)
        return
    }
    fmt.Println(string(body1[:]))
}