Go Web Programming: [04/01] Process FORM Inputs
Process form inputs
먼저 사용자가 입력한 양식 전송의 예를 살펴 보겠습니다. 다음과 같은 양식의 내용이 있다고 가정 합니다.
다음의 내용을 login.gtpl
파일로 생성합니다.(새로운 디렉토리를 만들고 그 안에 넣어주세요)
<html>
<head>
<title></title>
</head>
<body>
<form action="/login" method="post">
이름 : <input type="text" name="username">
암호 : <input type="password" name="password">
<input type="submit" value="로그인">
</form>
</body>
</html>
상기에서 작성한 페이지에서 내용을 입력 후 전송 버튼을 누르면 양식은 서버의 /login
에 전달 됩니다.
사용자가 정보를 입력하고 로그인을 클릭 하면, 서버의 login
으로 그 입력 데이터를 리디렉션 합니다.
먼저 전송방법
이 POST/GET
인지를 판단해야 합니다.
http
패키지를 통하면 아주 쉽게 이것을 처리할 수 있습니다. 이전 장에서 설명한 예제를 기초로해서
login 페이지의 form 데이터를 어떻게 처리하는지 살펴 보겠습니다.
package main
import (
"fmt"
"html/template"
"log"
"net/http"
"strings"
)
func sayhelloName(w http.ResponseWriter, r *http.Request) {
r.ParseForm() // url의 전달 옵션을 분석 합니다.
// POST방식일 경우 응답 패킷의 바디를 분석 합니다.(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 Xenostream!") // w에 기록하게되면 클라이언트에 출력 됩니다.
}
func login(w http.ResponseWriter, r *http.Request) {
fmt.Println("method :", r.Method) // 요청 처리 방식
if r.Method == "GET" {
t , _ := template.ParseFiles("login.gtpl")
t.Execute(w, nil)
} else {
// 로그인 데이터가 요청되고, 로그인 처리로직이 실행됩니다.
fmt.Println("username :", r.Form["username"])
fmt.Println("password :", r.Form["password"])
}
}
func main() {
http.HandleFunc("/", sayhelloName) // 라우팅을 설정합니다
http.HandleFunc("/login", login) // 라우팅을 설정합니다
err := http.ListenAndServe(": 9090", nil) // 감시하는 포트를 설정 합니다
if err != nil {
log.Fatal("ListenAndServe :", err)
}
}
위의 코드에서 사용자의 요청 메소드를 구하려면 단지 r.Method
메소드만 호출함으로 모든
처리가 완료됩니다. 이 메소드의 반환값은 문자열 변수
입니다.
GET, POST, PUT
등의 요청 method 정보를 반환 합니다.
login 함수에서 r.Method
의 반환값에 따라 로그인 화면표시와 로그인 로직을 처리할지를
결정하게 됩니다. GET
메소드에 의한 요청일 경우 로그인 화면을 표시하고, 다른 방법에 의한 요청은
로그인 로직을 처리 합니다. 예를 들어 데이터베이스를 검색하거나 로그인 정보를 확인하는 등의 일 입니다.
브라우저에서 http:/127.0.0.1:9090/login
을 입력하면 다음과 같은 화면이 나타납니다.
그림 4.1 사용자 로그인 화면
사용자 이름과 암호를 입력해도 서버는 아무것도 출력하지 않습니다. 왜 일까요?
기본적으로는 Handler에서는 form의 내용을 자동으로 분석하지 않기 때문 입니다.
반드시 명시적으로 r.ParseForm()
메소드를 호출하지 않는다면, 아무 데이터도 분석하지 않게 됩니다.
이제, 코드를 약간 수정
하여 fmt.Println("username :", r.Form["username"])
앞부분에
r.ParseForm()
코드를 추가하시기 바랍니다.
다시 컴파일한 후 정보를 입력하면 서버가 사용자가 입력 한,사용자 이름
과 암호
를 정상적으로 출력하게 됩니다.
r.Form
에는 사용자가 입력했던 모든 요청의 데이터가 모두 포함되어 있습니다. 예를 들어 URL에 입력한
query-string, POST 데이터, PUT 데이터
등 입니다. URL의 query-string
필드 및 POST
데이터가
충돌하는 경우에는 slice에 저장 됩니다. 여기에는 여러가지 값이 저장되어 있습니다.
Go의 공식 문서
에 따르면, 다음 버전에서 POST, GET 등의 데이터를 분리해서 저장한다고 밝힌바 있습니다.
이제는 login.gtpl
의 form의 action 값인 http:/127.0.0.1:9090/login
을
http:/127.0.0.1:9090/login?username=xenostream
으로 변경한 후 다시 시도하면, 서버의 출력은
다음과 같습니다.
그림 4.1 서버가 수신 한 데이터를 표시
request.Form
은 url.Values 형 입니다.key = value
구조로 해당 데이터가 저장되어 있습니다.
form 데이터에 어떤것이 있는지 간단한 몇 가지 예제를 살펴보겠습니다.
v := url.Values{}
v.Set("name", "Ava")
v.Add("friend", "Jess")
v.Add("friend", "Sarah")
v.Add("friend", "Zoe")
// v.Encode () == "name = Ava & friend = Jess & friend = Sarah & friend = Zoe"
fmt.Println(v.Get("name"))
fmt.Println(v.Get("friend"))
fmt.Println(v["friend"])
Tips
Request
패키지의 FormValue()
함수에서도 사용자가 전송한 데이터를 얻을 수 있습니다.
예를 들어 r.Form["username"]
은 r.FormValue("username")
로도 쓸수 있습니다. r.FormValue
를
호출할때 자동으로 r.ParseForm
이 호출되므로 미리 호출 할 필요는 없습니다.
r.FormValue
는 동일한 데이터 중에서 첫번째 데이터를 반환 합니다. 만약 데이터가 존재하지 않는 경우는
빈 문자열
을 반환 합니다.