天天看點

asp.net接受表單驗證格式後再送出資料_Go 語言 Web 程式設計系列——擷取使用者請求資料(上)

0、GET/POST 請求資料

在 PHP 中,可以直接通過全局變量 $_GET 和 $_POST 快速擷取 GET/POST 請求資料,GET 請求資料主要是 URL 查詢字元串中包含的參數,以前面線上論壇項目的群組詳情頁為例:

http://localhost:8080/thread/read?id=adb02107-d7c3-4f27-4de4-b586f231380e
           

上述 URL 請求中的 id=adb02107-d7c3-4f27-4de4-b586f231380e 就屬于 GET 請求資料,也就是查詢字元串,而對于使用者登入表單:

asp.net接受表單驗證格式後再送出資料_Go 語言 Web 程式設計系列——擷取使用者請求資料(上)

當使用者輸入注冊郵箱和密碼後點選「登入」按鈕,會将輸入框中的資料作為請求實體發送 POST 請求到服務端,執行登入認證,這裡的表單資料就是 POST 請求資料,如果我們檢視表單請求路由的 HTTP 封包:

asp.net接受表單驗證格式後再送出資料_Go 語言 Web 程式設計系列——擷取使用者請求資料(上)

就會看到表單請求資料,也就是上文提到的 HTTP 請求實體。

當然根據對服務端資源的操作類型不同,可以進一步細分為 POST、PUT、PATCH、DELETE 等包含請求實體的請求方法,為了簡化模型,我們這裡隻讨論 POST 請求,而且其他幾種請求方法也可以統一通過 POST 請求完成,通常隻有在設計遵循 RESTful 風格的 API 接口時,才會嚴格劃分不同的請求方法,關于這一點,後面介紹 REST + JSON 接口時再詳細讨論。

1、Form

Go 語言中擷取使用者請求資料的方式要更複雜一些,Go 也為此提供多個不同的結構體幫助我們讀取不同請求類型的資料,首先,我們可以通過請求對象上的 Form 讀取所有 GET/POST 請求資料,在 handlers/post.go 中新增 EditPost 方法如下:

func EditPost(w http.ResponseWriter, r *http.Request)  {    r.ParseForm()    fmt.Fprintln(w, r.Form)}
           

需要注意的是,在通過 r.Form 擷取所有請求資料之前,必須要先通過 r.ParseForm() 解析所有請求資料,否則無法擷取資料。

在 routes/web.go 中新增一個路由:

WebRoute{    "UpdatePost",    "POST",    "/post/edit",    handlers.EditPost,},
           

然後我們重新開機 HTTP 伺服器,在指令行通過 curl 發起一個包含不同類型請求資料的請求:

asp.net接受表單驗證格式後再送出資料_Go 語言 Web 程式設計系列——擷取使用者請求資料(上)

可以看到,列印結果表明 r.Form 是一個包含所有請求資料的字典類型(map),包含 URL 查詢字元串和 POST 請求資料,這是一個 POST 請求,如果是 GET 請求呢?我們為 EditPost定義一個 GET 請求路由:

WebRoute{    "EditPost",    "GET",    "/post/edit",    handlers.EditPost,},
           

再重新開機 HTTP 伺服器,發起一個隻包含查詢字元串的 GET 請求(預設是 GET 請求,不需要通過 -X GET 指定):

asp.net接受表單驗證格式後再送出資料_Go 語言 Web 程式設計系列——擷取使用者請求資料(上)

同樣可以列印出和 POST 請求完全一樣的結果。

是以,request 對象上的 Form 可以擷取所有請求參數,包括查詢字元串和請求實體,并且不限請求類型。如果你想要進一步要擷取指定的參數值,可以以索引方式擷取指定參數對應的值,也可以通過 Form 提供的 Get 方法,就像我們從一個普通字典類型擷取鍵值一樣:

id1 := r.Form["id"]id2 := r.Form.Get("id")fmt.Println(id1)fmt.Println(id2)
           

隻不過兩者的傳回值類型不一樣,前者是一個字元串切片,後者是一個字元串值:

[1]1
           

2、PostForm

上面的結果同時傳回了查詢字元串和請求實體,如果隻想擷取請求實體(即 POST 表單中的資料),可以通過 PostForm 實作:

func EditPost(w http.ResponseWriter, r *http.Request)  {    r.ParseForm()    id := r.Form.Get("id")    fmt.Println("post id:", id)    fmt.Println("form data:", r.PostForm)    io.WriteString(w, "表單送出成功")}
           

這樣一來,就隻能擷取到 POST 資料了:

asp.net接受表單驗證格式後再送出資料_Go 語言 Web 程式設計系列——擷取使用者請求資料(上)

然後在 HTTP 伺服器日志,可以看到如下答應結果:

asp.net接受表單驗證格式後再送出資料_Go 語言 Web 程式設計系列——擷取使用者請求資料(上)

可以看到 r.PostForm 傳回的也是字典類型資料,資料格式和 r.Form 完全一緻,并且這次隻包含了 POST 表單請求資料,不包含 URL 查詢字元串,也就是說,通過 r.PostForm 隻能擷取 POST 請求資料(請求實體資料),無法擷取 GET 請求資料(查詢字元串中的資料),你可以再次發起 GET 請求進行驗證:

asp.net接受表單驗證格式後再送出資料_Go 語言 Web 程式設計系列——擷取使用者請求資料(上)

這個時候,可以看到伺服器列印日志之包含 id 資訊,表單資訊為空:

asp.net接受表單驗證格式後再送出資料_Go 語言 Web 程式設計系列——擷取使用者請求資料(上)

通過 PostForm 擷取具體參數值的方式和 Form 一樣,這裡就不再贅述了:

title := r.PostForm.Get("title")content := r.PostForm.Get("content")
           

實際上,我們在前面的線上論壇項目中,就是通過這個方式擷取表單請求資料的:

err := request.ParseForm()user, err := models.UserByEmail(request.PostFormValue("email"))
           

3、FormValue/PostFormValue

最後,還可以通過 FormValue 和 PostFormValue 擷取使用者請求資料,使用它們的好處是不再需要單獨調用 ParseForm 對表單資料進行解析,不過使用這兩個方法的時候隻能擷取特定請求資料,不能一次擷取所有請求資料:

func EditPost(w http.ResponseWriter, r *http.Request)  {    fmt.Println("post id:", r.FormValue("id"))    fmt.Println("post title:", r.PostFormValue("title"))    fmt.Println("post title:", r.PostFormValue("content"))    io.WriteString(w, "表單送出成功")}
           

FormValue/PostFormValue 的差別和 Form/PostForm 一樣,這裡通過命名就可以看出來,前者可以擷取所有 GET/POST 請求資料(即查詢字元串和請求實體),後者隻能擷取 POST 請求實體資料。

注:FormValue/PostFormValue 之是以不用顯式調用 ParseForm 解析請求資料,是因為底層對其進行了封裝,實際上還是要調用這個方法。

4、擷取 JSON 請求資料

上面的示例預設都是基于 HTML 表單請求,對于用戶端送出的 JSON 格式資料,使用ParseForm 是無法解析并擷取資料的,因為 HTML 表單請求資料預設是通過 application/x-www-form-urlencoded 編碼的,而 JSON 請求資料通常是通過 application/json 編碼,ParseForm 隻能解析通過 application/x-www-form-urlencoded 編碼的資料。

對于 JSON 請求資料的解析,目前我們可以通過上篇教程介紹的,讀取完整請求實體并進行 JSON 解碼實作,下面我們改寫 AddPost 方法實作如下:

type Post struct {    Title string `json:"title"`    Content string `json:"content"`}func AddPost(w http.ResponseWriter, r *http.Request)  {    len := r.ContentLength   // 擷取請求實體長度    body := make([]byte, len)  // 建立存放請求實體的位元組切片    r.Body.Read(body)        // 調用 Read 方法讀取請求實體并将傳回内容存放到上面建立的位元組切片    // io.WriteString(w, string(body))    post := Post{}    json.Unmarshal(body, &post)  // 對讀取的 JSON 資料進行解析    fmt.Fprintf(w, "%#v", post)   // 格式化輸出結果}
           

我們将讀取的請求實體資料通過 JSON 解碼映射到 Post 結構體對象并将其輸出到響應結果。

重新開機 HTTP 伺服器,通過 curl 模拟用戶端送出 JSON 請求資料:

asp.net接受表單驗證格式後再送出資料_Go 語言 Web 程式設計系列——擷取使用者請求資料(上)

我們通過 -H 選項指定請求資料編碼格式為 application/json,然後請求資料調整為 JSON 格式字元串,最後通過輸出結果可以看到在服務端 JSON 請求資料已經可以成功解析并擷取。

5、小結

到這裡,我們已經了解了在 Go Web 程式設計中,常見的使用者請求資料如何解析并擷取(URL 查詢字元串、POST 表單資料、JSON 請求資料),實際上,和 PHP 中的 $_GET 和 $_POST 類似,Go 也是将 HTTP 請求資料映射到請求對象對應的結構體,然後開發者可以從上下文請求對象中解析并讀取這些請求資料,使用這些封裝好的對象的好處是它們屏蔽了底層的細節,統一了資料格式,可以大大提高開發效率,減少不必要的資料格式相容成本。

下篇教程,學院君将給大家介紹如何從表單請求中擷取檔案資料,并實作簡單的檔案上傳功能。

(全文完)

繼續閱讀