草庐IT

go - 在 handlefunc 之外安全终止请求

coder 2024-07-06 原文

如何在不在 handlefunc 中显式返回的情况下安全地终止调度程序 (handlefunc) 之外的请求?在下面的代码中,我最终在响应中同时看到“Bad request”和“Not found”,但我希望 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)
}

最佳答案

我不认为尝试从一个函数中中止是你想要在这里做的。相反,减少验证的重复性。您可以使用 func Require(form url.Values, required ...string) error 编写类似 package validate 的代码,并且在您的处理程序中,if err : = validate.Require(r.Form, "foo", "bar");错误!= 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 提出了一个棘手的问题,即当您的应用程序变得更加复杂时,在获得“框架”之前您可以抽象验证多少,而我没有一个简单的答案。


有些情况下确实会发生意外,服务器只能向用户提供不透明的“500 Internal Server Error”响应,但问题在您的 HandlerFunc 的深处显现。典型的例子是像 nil 指针取消引用这样的编程错误。 The advice from the Go team是在“错误不可恢复”时使用panic。 (像 negroni.Recovery 这样的工具可以帮助记录 panic 等)

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

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

我做了一个快速的 grep 并且基本上所有对标准库和其他官方存储库中的 panic 的调用都是为了捕获编程/内部错误,而不是在意外的外部崩溃输入错误或 I/O 错误等情况。诸如未找到文件/对象或无效用户输入之类的事情通常可以比通过崩溃请求更优雅地处理(至少有可能返回特定错误),并且它们并不是真正出乎意料(这是互联网;你会得到无效的输入和对不存在的事物的请求)。所以 panic 不是正常的请求中止——它是为了当“不可能发生”的事情发生并且请求无法继续时崩溃。


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

关于go - 在 handlefunc 之外安全终止请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26867307/

有关go - 在 handlefunc 之外安全终止请求的更多相关文章

  1. ruby - 如何使用 Ruby aws/s3 Gem 生成安全 URL 以从 s3 下载文件 - 2

    我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A

  2. ruby-on-rails - Rails HTML 请求渲染 JSON - 2

    在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这

  3. jquery - 我的 jquery AJAX POST 请求无需发送 Authenticity Token (Rails) - 2

    rails中是否有任何规定允许站点的所有AJAXPOST请求在没有authenticity_token的情况下通过?我有一个调用Controller方法的JqueryPOSTajax调用,但我没有在其中放置任何真实性代码,但调用成功。我的ApplicationController确实有'request_forgery_protection'并且我已经改变了config.action_controller.consider_all_requests_local在我的environments/development.rb中为false我还搜索了我的代码以确保我没有重载ajaxSend来发送

  4. ruby - 如何安全地删除文件? - 2

    在Ruby中是否有Gem或安全删除文件的方法?我想避免系统上可能不存在的外部程序。“安全删除”指的是覆盖文件内容。 最佳答案 如果您使用的是*nix,一个很好的方法是使用exec/open3/open4调用shred:`shred-fxuz#{filename}`http://www.gnu.org/s/coreutils/manual/html_node/shred-invocation.html检查这个类似的帖子:Writingafileshredderinpythonorruby?

  5. ruby - 用 YAML.load 解析 json 安全吗? - 2

    我正在使用ruby2.1.0我有一个json文件。例如:test.json{"item":[{"apple":1},{"banana":2}]}用YAML.load加载这个文件安全吗?YAML.load(File.read('test.json'))我正在尝试加载一个json或yaml格式的文件。 最佳答案 YAML可以加载JSONYAML.load('{"something":"test","other":4}')=>{"something"=>"test","other"=>4}JSON将无法加载YAML。JSON.load("

  6. ruby - HTTP 请求中的用户代理,Ruby - 2

    我是Ruby的新手。我试过查看在线文档,但没有找到任何有效的方法。我想在以下HTTP请求botget_response()和get()中包含一个用户代理。有人可以指出我正确的方向吗?#PreliminarycheckthatProggitisupcheck=Net::HTTP.get_response(URI.parse(proggit_url))ifcheck.code!="200"puts"ErrorcontactingProggit"returnend#Attempttogetthejsonresponse=Net::HTTP.get(URI.parse(proggit_url)

  7. ruby-on-rails - 安全地显示使用回形针 gem 上传的图像 - 2

    默认情况下:回形针gem将所有附件存储在公共(public)目录中。出于安全原因,我不想将附件存储在公共(public)目录中,所以我将它们保存在应用程序根目录的uploads目录中:classPost我没有指定url选项,因为我不希望每个图像附件都有一个url。如果指定了url:那么拥有该url的任何人都可以访问该图像。这是不安全的。在user#show页面中:我想实际显示图像。如果我使用所有回形针默认设置,那么我可以这样做,因为图像将在公共(public)目录中并且图像将具有一个url:Someimage:看来,如果我将图像附件保存在公共(public)目录之外并且不指定url(同

  8. ruby-on-rails - 获取并发布相同匹配项的请求 - 2

    在我的路线文件中我有:match'graphs/(:id(/:action))'=>'graphs#(:action)'如果是GET请求(工作)或POST请求(不工作),我想匹配它我知道我可以使用以下方法在资源中声明POST请求:post'/'=>:show,:on=>:member但是我怎样才能为比赛做到这一点呢?谢谢。 最佳答案 如果你同时想要POST和GETmatch'graphs/(:id(/:action))'=>'graphs#(:action)',:via=>[:get,:post]编辑默认值可以设置如下match'g

  9. ruby - 为什么允许在 Ruby 类之外定义全局方法? - 2

    我读过这个:Let’sstartwithasimpleRubyprogram.We’llwriteamethodthatreturnsacheery,personalizedgreeting.defsay_goodnight(name)result="Goodnight,"+namereturnresultend我的理解是,方法是定义在类中的函数或子程序,可以关联到类(类方法)或对象(实例方法)。那么,如果它不是在类中定义的,怎么可能是方法呢? 最佳答案 当你在Ruby中以这种方式在全局范围内定义一个函数时,它在技术上变成了Obje

  10. Ruby 服务器在本地主机(teambox)之外非常慢 - 2

    我刚刚在我的Ubuntu9.10服务器上安装了TeamBox。我使用提供的服务器脚本在端口3000上启动并运行它。它的运行速度非常慢,从另一台计算机连接时每个HTTP请求最多需要30秒。我使用链接从shell加载TeamBox,一点也不花时间。然后我设置了一个SSH隧道,它再次运行得非常快。我通过此服务器上的apache以及SAMBA等运行了大约30个虚拟主机,没有任何问题。我该如何解决这个问题? 最佳答案 我的redmine(ruby,webrick)太慢了。现在我解决了这个问题:apt-getinstallmongrelruby

随机推荐