2021/02/24 - [Go] - Golang으로 web application 구현하기 1

 

간단한 웹 서버를 만들어보자.

메인 메서드는 http.HandleFunc로 호출할 수 있다.
해당 메서드는  http 패키지가 핸들러를 이용해 루트( / ) 에 대한 모든 요청을 처리하도록 한다.

메인 메서드는 http.ListenAndServe 를 호출하는데 이는 모든 인터페이스의 포트 8080에서 수신하도록 지정한다.

// +build ignore

package main

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

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}

func main() {
    http.HandleFunc("/", handler)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

ListenAndServe는 예상치 못한 경우의 수가 나타나면 항상 에러를 반환하는데 
해당 오류를 기록하기 위해 함수 호출을 log.Fatal로 감싸서 표현한다.

위에서 handler는 http.HandlerFunc타입이다. 해당 핸들러는 http.ResponseWriter , http.Request를 인스로 사용한다.

http.ResponseWriter는 Http 서버의 응답을 조합해여, Http client에 데이터를 보내는 역할을 한다.

http.Request는 client의 Http 요청을 나타내는 데이터 구조이다.
r.URL.Path는 URL 요청에 대한 path 정보를 담고 있다.
뒤에 붙은 [1:]의 의미는 첫번째 문자에서 끝까지 Path의 하위 sub-slice 를 만든다는 뜻이다.
이렇게 하면 이름에서 선행 '/' 가 path에서 삭제된다.
쉽게 설명해서 아래와 같은 프로그램 URL로 요청하게되면

http://localhost:8080/monkeys

해당 프로그램은 아래처럼 결과가 나오게 된다는 의미다.

Hi there, I love monkeys!

 

그럼 우리가 만든 wiki page 에 위에서 설명한 net/http를 대입해보자.
먼저 net/http 를 import 추가해준다.

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
)

그리고, handler를 구현해보자.
viewHandler 는 사용자가 해당 페이지를 볼 수 있도록 한다.
"/view/"로 시작하는 URL들을 처리할 것이다. 아래 처럼 코드를 수정하자.

func viewHandler(w http.ResponseWriter, r *http.Request) {
    title := r.URL.Path[len("/view/"):]
    p, _ := loadPage(title)
    fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body)
}

앞서도 언급했지만,  _ 는 loadPage로 부터 error 가 발생 했을 경우 이를 무시한다.
원래는 위처럼 처리하면 안됨!! 하지만 우리는 간단하게 구현하기 위해서 해당 코드로 테스트 해보자.

먼저, 이 함수는 r.URL.Path에서 페이지 제목을 가져온다.
Path는 [len("/view/"):] 에 의해서 다시 분리되고 앞에 view는 제거된다.
경로는 항상 페이지 제목의 일부가 아닌 /view/ 로 시작하는 것으로 정의했기 때문이다.

/view/ 경로 아래 요청을 처리하기 위해 viewHandler 를 사용해서 http를 초기화 하는 메인 함수를 다시 작성한다.

func main() {
    http.HandleFunc("/view/", viewHandler)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

전체코드는 아래와 같다.

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
)

type Page struct {
	Title string
	Body  []byte
}

func (p *Page) save() error {
	filename := p.Title + ".txt"
	return ioutil.WriteFile(filename, p.Body, 0600)
}

func loadPage(title string) (*Page, error) {
	filename := title + ".txt"
	body, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return &Page{Title: title, Body: body}, nil
}

func viewHandler(w http.ResponseWriter, r *http.Request) {
	title := r.URL.Path[len("/view/"):]
	p, _ := loadPage(title)
	fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body)
}

func main() {
	http.HandleFunc("/view/", viewHandler)
	log.Fatal(http.ListenAndServe(":8080", nil))
}

테스트 하기 위한 페이지 데이터를 임시로 만들고(test.txt), 코드를 컴파일해서 위키 페이지를 다시 호출해보자.
test.txt 의 내용은 "Hello World" 로 작성한다.

$ go build wiki.go
$ ./wiki

이제 http://localhost:8080/view/test 로 접근해보자.
아래 처럼 화면이 나온다면 성공!!

+ Recent posts