Перехват условия ошибки в каждом обработчике вводит много повторяющегося кода. Что если бы мы могли обернуть каждый из обработчиков в функцию, которая делает валидацию и проверку ошибок? Литералы Go функций предоставляют мощные средства абстрагирования функциональности и это может помочь нам здесь.
Сначала мы переписываем определение функции каждого из обработчиков, чтобы принимать строку заголовка:
func viewHandler(w http.ResponseWriter,
r *http.Request, title string)
func editHandler(w http.ResponseWriter,
r *http.Request, title string)
func saveHandler(w http.ResponseWriter,
r *http.Request, title string)
Теперь давайте определим функцию-обертку, которая принимает функцию верхнего типа и возвращает функцию типа http.HandlerFunc
(подходит для передачи в функцию http.HandleFunc
):
func makeHandler(fn func (http.ResponseWriter,
*http.Request, string)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Здесь мы извлечем заголовок страницы из запроса,
// и вызываем предоставленный обработчик 'fn'
}
}
Возвращенная функция называется замыканием, потому что она содержит значения, определенные вне функции. В этом случае переменная fn
(единственный аргумент makeHandler
) заключен в замыкание. Переменная fn
будет одним из наших обработчиков сохранения, редактирования или просмотра.
Теперь мы можем взять код из getTitle
и использовать его здесь (с некоторыми незначительными изменениями):
func makeHandler(fn func(http.ResponseWriter,
*http.Request, string)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
m := validPath.FindStringSubmatch(r.URL.Path)
if m == nil {
http.NotFound(w, r)
return
}
fn(w, r, m[2])
}
}
Замыкание, возвращаемое makeHandler
, является функцией, которая принимает http.ResponseWriter
и http.Request
(другими словами, http.HandlerFunc
). Замыкание извлекает title
из пути запроса и проверяет его с помощью TitleValidator
regexp. Если title
недействителен, ошибка будет записана в ResponseWriter
с помощью функции http.NotFound
. Если title
допустим, вложенная функция-обработчик fn
будет вызываться с помощью ResponseWriter
, Request
и title
в качестве аргументов.
Теперь мы можем обернуть функции-обработчики с помощью makeHandler
в main
, прежде чем они будут зарегистрированы в http
пакете:
func main() {
http.HandleFunc("/view/", makeHandler(viewHandler))
http.HandleFunc("/edit/", makeHandler(editHandler))
http.HandleFunc("/save/", makeHandler(saveHandler))
log.Fatal(http.ListenAndServe(":8080", nil))
}
Наконец, мы удаляем вызовы getTitle
из функций обработчиков, делая их намного проще:
func viewHandler(w http.ResponseWriter,
r *http.Request, title string) {
p, err := loadPage(title)
if err != nil {
http.Redirect(w, r, "/edit/"+title,
http.StatusFound)
return
}
renderTemplate(w, "view", p)
}
func editHandler(w http.ResponseWriter,
r *http.Request, title string) {
p, err := loadPage(title)
if err != nil {
p = &Page{Title: title}
}
renderTemplate(w, "edit", p)
}
func saveHandler(w http.ResponseWriter,
r *http.Request, title string) {
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)
}
Читайте также:
- Веб-приложение на Go: использование net/http для обслуживания вики-страниц
- Веб-приложение на Go: редактирование страниц, пакет html/template
- Веб-приложение на Go: валидация
Комментариев нет:
Отправить комментарий