在handlefunc之外安全地终止请求

时间:2014-11-11 14:35:18

标签: go

如何在handlefunc中没有显式返回的情况下,在调度程序(handlefunc)之外安全地终止请求?在下面的代码中,我最终在我的响应中看到“错误请求”和“未找到”,但我希望f()中止请求 - 所以我不必将调度程序与错误检查混淆回报。

package main

import (
    "net/http"
)

func f(w http.ResponseWriter, r *http.Request, k string) string{
    if v, ok := r.Form[k]; !ok{     
        http.Error(w, "Bad request", http.StatusBadRequest)
        return ""
    }else{
        return v[0]
    }
}

func main(){
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request){
        foo := f(w, r, "foo") //make sure foo is passed, if not abort with "bad request" without requiring an explicit return here
        bar := f(w, r, "bar") //make sure bar is passed, if not abort with "bad request" without requiring an explicit return here
        //lookup in db...
        //abort with a 404 if not found in db
        http.NotFound(w, r)         
    })  

    http.ListenAndServe(":6000", nil)
}

以上是尝试重构以下内容:

func main(){
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request){
        if foo,ok:=r.Form["foo"];!ok{
            http.Error(w, "Bad request", http.StatusBadRequest)
            return
        }
        if bar,ok:=r.Form["bar"];!ok{
            http.Error(w, "Bad request", http.StatusBadRequest)
            return
        }
        //lookup in db...
        //abort with a 404 if not found in db
        http.NotFound(w, r)         
    })  

    http.ListenAndServe(":6000", nil)
}

1 个答案:

答案 0 :(得分:2)

我不认为试图在功能中输入是你想要在这里做的。相反,使验证更少重复。您可以使用package validate编写类似func Require(form url.Values, required ...string) error的内容,并在处理程序中编写if err := validate.Require(r.Form, "foo", "bar"); err != nil { ... }

或者你可以做一个更通用的验证器:可以将map字段名称用于验证类型(数字,字符串等)并返回另一个map nil如果没有错误,则为{"fieldName": error}

Redditors talked some about this,其中一人写了a library that uses struct tags to validate。在new form rendering/validation toolkit中有另一个基于结构的验证实现。 (我也没试过。)Redditors提出了一个棘手的问题,即在获得一个"框架之前你可以抽象多少验证。当你的应用程序变得更加复杂时,这会妨碍我,并且我没有简单的答案。


在某些情况下,某些事情会发生意外情况,并且服务器无法做任何更好的事情而不是给用户一个不透明的内部服务器错误"响应,但问题显示在HandlerFunc以下。规范示例是编程错误,如nil指针取消引用。 The advice from the Go team将在{&#34}时使用panic,错误无法恢复。" (像negroni.Recovery这样的工具可以帮助记录panic等。)

不必要的panic是蹩脚的,因为:

  • panic让您更容易完全忘记必要的错误处理,因为暗示事情可以panic显式他们可以err
  • panic / recover错误处理代码难看且难以维护
  • panic引入了与标准err返回
  • 的不一致
  • panic使用堆栈展开,这比正常控制流慢得多

我做了一个快速的grep,基本上所有对标准库中的panic的调用和其他官方存储库都可以捕获编程/内部错误,而不是在输入错误或我输入的意外外部条件下崩溃/ O错误。找不到文件/对象或无效的用户输入通常可以比崩溃请求更优雅地处理(它至少可能返回特定错误),并且它们并非真正意外(它&# 39;互联网;你会得到无效的输入和对不存在的东西的请求。因此,对于正常的请求中止,panic - 当发生的事情无法发生时,它会崩溃。"已经发生,请求无法继续。


同样,在这里,我在处理程序函数中使用标准if块处理无效输入,但重新安排验证,以便它不需要每个必需参数的大量代码。