3탄까지 진행한 후 없는 페이지로 접근하면 어떻게 될까? 빈 HTML 화면이 노출된다.
이는 loadPage의 오류 반환 값을 무시하고 계속해서 데이터없이 템플릿을 채우려고 하기 때문이다.
만약 페이지가 존지하지 않는다면 edit page로 redirect 하도록 코드를 수정해보자.

func viewHandler(w http.ResponseWriter, r *http.Request) {
    title := r.URL.Path[len("/view/"):]
    p, err := loadPage(title)
    if err != nil {
        http.Redirect(w, r, "/edit/"+title, http.StatusFound)
        return
    }
    renderTemplate(w, "view", p)
}

http.Redirect 함수는 HTTP 상태 코드 http.StatusFound (302)와 Location 헤더를 HTTP 응답에 추가한다.
그리고 빌드 후 없는 url로 요청을 해보자.


localhost:8080/view/123123

 

view로 없는 페이지를 요청했더니, 정상적으로 edit 페이지로 리다이렉트 되는 것을 확인가능!

그럼 이제 저장 handler를 구현해보자.
saveHandler 는 edit 페이지의 form을 받아서 저장하는 로직을 처리한다.
main 메소드의 주석 부분을 제거하고 구현해보자.

func saveHandler(w http.ResponseWriter, r *http.Request) {
    title := r.URL.Path[len("/save/"):]
    body := r.FormValue("body")
    p := &Page{Title: title, Body: []byte(body)}
    p.save()
    http.Redirect(w, r, "/view/"+title, http.StatusFound)
}

URL로 요청한 부분을 페이지 Title로 , 유일한 필드인 본문이 Body 값으로 전달되어 새로운 페이지를 생성한다.
save 메서드는 file에 우리가 요청한 부분을 작성하고 client 는 /view/ page로 리다이렉트 된다.
이때 FormValue에서 반환하는 값은 문자열(String)이다. 
Page struct에 들어가기 전에 []byte 로 변환해야 한다. []byte (body) 로 형변환을 해줌! 


우리는 간단한 테스트 구현을 위해서 몇몇 error가 발생할 수 있는 로직을 그냥 무시했다.
이제, 해당 부분을 수정해보자. 오류를 처리하고 오류메세지를 사용자에게 전달함으로써 서버가 우리가 원하는 방식으로 잘 동작하고 있는지 사용자에게 알릴 수 있다.

좀 전에 작성한 saveHandler 코드를 아래와 같이 수정하자.

 

func saveHandler(w http.ResponseWriter, r *http.Request) {
    title := r.URL.Path[len("/save/"):]
    body := r.FormValue("body")
    p := &Page{Title: title, Body: []byte(body)}
    err := p.save()
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    http.Redirect(w, r, "/view/"+title, http.StatusFound)
}

 

근데, 우리가 작성한 코드를 다시 살펴보면 비효율 적인 부분을 발견할 수 있다.
renderTamplate의 경우 페이지가 렌더링될 때마다 ParseFile을 호출한다.
보다 효율적인 방법은 프로그램이 시작될때 딱 한 번 모든 *Template를 읽어오도록 하는 것이다.
그런 다음 ExecuteTemplate 메서드를 사용해서 특정 템플릿만 렌드링할 수 있다.

그럼 먼저 templates 이라는 전역 변수를 만들고 ParseFile로 초기화한다.

var templates = template.Must(template.ParseFiles("edit.html", "view.html"))

위의 함수 template.Must 는 nil이 아닌 오류값이 전달 되면 프로그램이 종료되고 그렇지 않을 경우 변경되지 않은 *Template를 반환한다. 이처럼 템플릿을 로드할 수 없는 경우에는 프로그램을 종료하는 것이 적절하다.
ParseFiles 함수는 템플릿 파일을 식별하는 문자열 인수를 받는다. 그리고 해당 파일이름으로 명명된 템플릿으로 구문을 분석한다.
프로그램에 템플릿을 더 추가하려면 해당 이름을 ParseFiles 호출의 인수에 추가하면 된다.


그런 다음 적절한 템플릿 이름으로 templates.ExecuteTemplate 메서드를 호출하도록 renderTemplate 함수를 수정해보자.
* 여기서 주의할 점은 템플릿의 이름은 템플릿 파일이름 이므로 tmpl 인수에 .html도 추가하여야한다.

func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
    err := templates.ExecuteTemplate(w, tmpl+".html", p)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
    }
}


 

+ Recent posts