原文链接: Golang发送post表单请求

golang这边将map结构序列化通常采用json.Marshal和json.Unmarshal来做,但是在php server端还需要做json反序列化解析才能用, 用golang模拟表单提交, php server端则非常方便提取相应的数据字段.
方法

方法是利用golangnet/http包提供的PostForm提交post表单提交。ParseForm解析URL中的查询字符串,并将解析结果更新到r.Form字段。对于POST或PUT请求,ParseForm还会将body当作表单解析,并将结果既更新到r.PostForm也更新到r.Form。解析结果中,POST或PUT请求主体要优先于URL查询字符串(同名变量,主体的值在查询字符串的值前面)。如果请求的主体的大小没有被MaxBytesReader函数设定限制,其大小默认限制为开头10MB。
http.Client{}.PostForm

利用http.Client{}.PostForm提交post表单。

import "net/http"
client := &http.Client{}
res, err := client.PostForm("http://127.0.0.1:8091/postpage", url.Values{
	"key":   {"this is client key"},
	"value": {"this is client value"},
})

http.PostForm

直接用http.PostForm提交post表单。

import "net/http"
//data := make(url.Values)
//data["key"] = []string{"this is key"}
//data["value"] = []string{"this is value"}
//把post表单发送给目标服务器
res, err := http.PostForm("http://127.0.0.1:8091/postpage", url.Values{
	"key":   {"this is url key"},
	"value": {"this is url value"},
})

对表单数据的提取

server端对表单数据的提取

//接受post请求, 然后打印表单中key和value字段的值
if r.Method == "POST" {
	var (
		key   string = r.PostFormValue("key")
		value string = r.PostFormValue("value")
	)

几个重要的变量
http.request 中涉及到数据解析的几个重要变量为:

	// Form contains the parsed form data, including both the URL
	// field's query parameters and the POST or PUT form data.
	// This field is only available after ParseForm is called.
	// The HTTP client ignores Form and uses Body instead.
	Form url.Values

	// PostForm contains the parsed form data from POST, PATCH,
	// or PUT body parameters.
	//
	// This field is only available after ParseForm is called.
	// The HTTP client ignores PostForm and uses Body instead.
	PostForm url.Values

	// MultipartForm is the parsed multipart form, including file uploads.
	// This field is only available after ParseMultipartForm is called.
	// The HTTP client ignores MultipartForm and uses Body instead.
	MultipartForm *multipart.Form
说明:
Form:存储了post、put和get参数,在使用之前需要调用 ParseForm 方法。
PostForm:存储了post、put参数,在使用之前需要调用 ParseForm 方法。
MultipartForm:存储了包含了文件上传的表单的post参数,在使用前需要调用 ParseMultipartForm 方法

获取 GET 参数

因为 Form 中同时存储了 GET 和 POST 请求的参数,所以最好不要用该变量来获取 GET 参数,取而代之的方法为:

queryForm, err := url.ParseQuery(r.URL.RawQuery)
if err == nil && len(queryForm["id"]) > 0 {
    fmt.Fprintln(w, queryForm["id"][0])
}

获取 POST 参数

1. application/x-www-form-urlencoded 格式


r.ParseForm()
// 法一
r.PostForm["id"][0]
// 法二
r.PostFormValue["id"]

2. multipart/form-data 格式

//  普通参数
r.ParseMultipartForm(32<<20)
// 法一
r.PostForm["id"][0]
// 法二
r.PostFormValue["id"]
// 3. 文件
	r.ParseMultipartForm(32 << 20)
	file, handler, err := r.FormFile("file")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer file.Close()
	fmt.Fprintf(w, "%v", handler.Header)
	f, err := os.OpenFile("./test.txt", os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer f.Close()
	io.Copy(f, file)

3. application/json 格式

type User struct {
	Name string `json:"username"`
	Pwd string `json:"password"`
}

type RetMessage struct {
	Code string `json:"code"`
	Msg string	`json:"msg"`
}

func processJson(w http.ResponseWriter, r *http.Request) {
	var u User
	if r.Body == nil {
		http.Error(w, "Please send a request body", 400)
		return
	}
	err := json.NewDecoder(r.Body).Decode(&u)
	if err != nil {
		http.Error(w, err.Error(), 400)
		return
	}
	fmt.Println(u)
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(RetMessage{"200", "ok"})
}