iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 14
1
Software Development

啥物碗Golang? 30天就Go系列 第 14

Post 表單

我們前幾天都一直在處理GET請求,今天我們來試著做一個POST表單範例,首先我們需要一個表單的HTML template。我們這次使用gtpl為副檔名,這是一個專門為了go所做的網頁框架,類似ruby的erb,如果想瞭解更多可以參考github

我們新建一個檔案,另存為login.grpl

<html>
  <head>
    <title></title>
  </head>
  <body>
    <form action="/login" method="post">
      Username:<input type="text" name="username">
      Password:<input type="password" name="password">
      <input type="submit" value="Submit">
    </form>
  </body>
</html>

很不幸的,vs code還沒有對gtpl有程式碼高亮支援。從這段程式可以看出這是一個簡單的登入頁面,包裹在一個POST的表單中,有兩個輸入欄位讓使用者輸入用戶名稱與密碼。這邊並沒有真的實作密碼驗證,只是單純把使用者輸入的值印在畫面上。有關與資料庫串接或session,在之後的日子應該會討論到。

接下來我們看看程式的部分:

package main

import (
	"fmt"
	"html/template"
	"log"
	"net/http"
)

func main() {
	http.HandleFunc("/login", login)
	err := http.ListenAndServe(":3000", nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

func login(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	fmt.Println("method:", r.Method)
	if r.Method == "GET" {
		t, _ := template.ParseFiles("./day14/login.gtpl")
		log.Println(t.Execute(w, nil))
	} else {
		// 在這邊放真實的驗證
		fmt.Fprint(w, "username: ", r.Form["username"][0])
		fmt.Fprint(w, ", password: ", r.Form["password"][0])
	}
}

這個範例相當的簡化,只有一個路由,但可以接受兩種action,分別是GET與POST,很符合我們常見的例子:GET作為表單的view本身,POST發送表單內容到後端。

要特別注意幾個地方,r.ParseForm()這個會解析request內POST的主體,並且把參數讀取出來。如果沒有加上的話編譯不會錯,但是會讀不到參數,使用POST的時候要特別注意!另外r.Method可以將action讀出來,判斷是GET或是POST進行不同邏輯。

如果我們訪問瀏覽器http://localhost:3000/login(透過瀏覽器時一定是GET),會得到下面的畫面:
login page
非常簡陋我知道,我們目前先不考慮美觀的部分。輸入名稱密碼後,會秀在頁面上:
login result

今天的範例就到這邊,想題目越來越困難啦,希望能繼續堅持下去!

Reference


上一篇
包 package
下一篇
Post 表單 2
系列文
啥物碗Golang? 30天就Go30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
eric19740521
iT邦新手 1 級 ‧ 2021-02-20 22:03:55

請問http.HandleFunc("/login", login) 這行程式是綁定 func login???

我寫了底下的程式


package main

import (
	"time"
    "fmt"
    "html/template"
    "log"
    "net/http"
    "strings"
)

func sayhelloName(w http.ResponseWriter, r *http.Request) {

	currentTime:=time.Now()  
	fmt.Println("home888============")
	fmt.Println(currentTime)   
    
	r.ParseForm()       //解析 url 傳遞的參數,對於 POST 則解析 HTTP 回應內容的主體(request body)
    //注意 : 如果沒有呼叫 ParseForm 方法,下面無法取得表單的資料
    fmt.Println(r.Form) //這些資訊是輸出到伺服器端的列印資訊
    fmt.Println("path", r.URL.Path)
    fmt.Println("scheme", r.URL.Scheme)
    fmt.Println(r.Form["url_long"])
    for k, v := range r.Form {
        fmt.Println("key:", k)
        fmt.Println("val:", strings.Join(v, ""))
    }
    fmt.Fprintf(w, "Hello astaxie!") //這個寫入到 w 的是輸出到客戶端的
}
func login(w http.ResponseWriter, r *http.Request) {
	currentTime:=time.Now()  
	fmt.Println("login============")
	fmt.Println(currentTime)   
	
	r.ParseForm()
    fmt.Println(r.Form) //這些資訊是輸出到伺服器端的列印資訊
    fmt.Println("path", r.URL.Path)
    fmt.Println("scheme", r.URL.Scheme)    
	
	
	
	fmt.Println("method:", r.Method) //取得請求的方法
    if r.Method == "GET" {
        t, _ := template.ParseFiles("login.gtpl")
        log.Println(t.Execute(w, nil))
    } else {
        //請求的是登入資料,那麼執行登入的邏輯判斷
		fmt.Fprint(w, "username: ", r.Form["username"][0])
		fmt.Fprint(w, ", password: ", r.Form["password"][0])
    }
}

func main() {
	fmt.Println("service start...") 
	
    //fmt.Println("path", r.URL.Path)
    //fmt.Println("scheme", r.URL.Scheme)
    http.HandleFunc("/", sayhelloName)       //設定存取的路由
    http.HandleFunc("/login", login)         //設定存取的路由
    err := http.ListenAndServe(":9099", nil) //設定監聽的埠
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

在瀏覽器輸入 http://127.0.0.1:9099/login

https://ithelp.ithome.com.tw/upload/images/20210220/20013294dR6QpgI40J.png

後端在處理的時候??還是會處理 home 函數
https://ithelp.ithome.com.tw/upload/images/20210220/20013294sS0EicSvSq.png

不知道哪行程式出錯了!!!

我要留言

立即登入留言