【问题标题】:In Go + FastCGI, does it make any sense to use multiple handlers?在 Go + FastCGI 中,使用多个处理程序是否有意义?
【发布时间】:2017-09-12 09:07:34
【问题描述】:

Gopher 新手在这里。请善待:-)

我有一个设置,我在共享服务器上有一个帐户,该服务器运行 Apache + FastCGI,我无法控制。不过,它可以顺利地与 Go 交互。我更习惯于将 Go 与 net/http 一起使用,但弄清楚如何将它与 net/http/fcgi 一起使用似乎很简单。这是我的最小测试应用程序:

package main

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

func handler(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    w.Header().Set("Content-type", "text/plain; charset=utf-8")
    fmt.Fprintln(w, "This was generated by Go running as a FastCGI app")
}

func main() {
    /*
     *  
     *  Everything that is done here should be setup code etc. which is retained between calls
     *  
     */
    http.HandleFunc("/", handler)
    // This is what actually concurrently handles requests
    if err := fcgi.Serve(nil, nil); err != nil {
            panic(err)
    }
}

现在它完美无瑕地工作了:在将其编译为 go-fcgi-test.fcgi 并将其放置在适当的目录下之后,Go 代码将从 http://my.shared.web.server/go-fcgi-test.fcgi 之类的 URL 运行。为了简单起见,我省略了大部分实际处理——但这与提取表单参数、ENV 变量(在 Go 1.9 下!)等方面完美配合,所以我知道基本设置必须没问题。

让我们尝试一个稍微复杂一点的例子:

package main

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

func handler1(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    w.Header().Set("Content-type", "text/plain; charset=utf-8")
    fmt.Fprintln(w, "This comes from handler1")
}

func handler2(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    w.Header().Set("Content-type", "text/plain; charset=utf-8")
    fmt.Fprintln(w, "This comes from handler2")
}

func main() {
    http.HandleFunc("/first", handler1)
    http.HandleFunc("/", handler2)
    if err := fcgi.Serve(nil, nil); err != nil {
            panic(err)
    }
}

现在,在这种情况下,我希望 http://my.shared.web.server/go-fcgi-test.fcgi 输出 This comes from handler2,而事实上,这正是发生的情况。

但是为什么http://my.shared.web.server/go-fcgi-test.fcgi/first 实际上也调用了handler2,即handler1 被完全忽略了?请注意,handler2 确实获得了 URL 的 /first 位——Apache 没有将其剥离——因为我可以读取 r.URL.Path[1:] 并确认这是发送到 Go 应用程序的整个路径。

我在网上找到的所有使用类似框架的 FastCGI 示例都只显示 一个 处理程序。这是 FastCGI 包本身的限制吗? FastCGI 协议的限制(但为什么正确发送整个路径?)?在 Apache 配置中做了什么强加了这个限制(记住,我不能触及 Apache 配置)?还是我做错了什么?

(为了完整起见,我应该补充一点,是的,我已经尝试了上面的几种变体,重命名 Go 应用程序,使用子文件夹,使用 几个 处理程序,而不仅仅是一个,等等.等等)

我的真实世界场景实际上是一个小型应用程序,它应该作为一个使用 net/http 的独立 Web 服务器运行在独立模型的情况下作为 FastCGI 应用程序运行要么不支持,要么甚至被禁止(某些共享环境的提供者就是这种情况)。由于这两种情况的实际处理完全相同,唯一的区别是调用fcgi.Serve() 而不是http.ListenAndServe()。但是如果能在 FastCGI 下使用 net/http 包的路由能力和不同的处理程序,那就太好了。

提前感谢您提供任何见解。即使答案是“是的,这正是在 Go 下 FastCGI 实现是如何工作的——只有一个处理程序!”这仍然很有用——这意味着我只需要处理我自己的代码并以不同的方式做事(基本上,根据通过 Form 接口传递的参数创建我自己的路由器/调度程序——没什么大不了的,这是可行的!)

【问题讨论】:

  • fcgi 只是提供 HTTP 服务器部分;处理程序及其注册由多路复用器提供,在这种情况下是标准的net/httpServeMux。它的行为不应该有任何不同,而且我不确定这两个处理程序是如何被调用的——它们都写入标头,所以由于标头已经发送,应该会感到恐慌。
  • 您确定对handler2 的调用是针对/first 而不是针对favicon.icohandler2,由于它的映射,将处理除 /first 之外的所有请求,所以我不会惊讶地看到它在同一页面视图上获得浏览器生成的辅助请求。

标签: go fastcgi


【解决方案1】:

我意识到这是一篇旧帖子,但我自己刚刚开始使用 Go 和 fcgi 并遇到了同样的问题。

简短的回答是肯定的,使用多个处理程序确实有意义。您的示例中的缺陷是您没有考虑到 go-fcgi-test.fcgi 是您 URL 的一部分。

当 Go 的 ServeMux 处理 URL 时,它使用请求的完整 URL,而不仅仅是 fcgi 进程正在处理的部分。对于http://my.shared.web.server/go-fcgi-test.fcgi/first,程序正在寻找与/go-fcgi-test.fcgi/first 最接近的匹配项,即/

【讨论】:

  • 感谢您的回答!我已经忘记了我其实问过这个问题嘿嘿......这让我重新阅读了documentation for ServeMux,我认为问题是我应该注册http.HandleFunc("/first/", handler1),i。 e.带有斜杠,否则我会得到您描述的行为...
【解决方案2】:

看完@Kodiak提供的答案后,我重新阅读了documentation for ServeMux并遇到了这一段:

请注意,由于以斜杠结尾的模式命名了根子树,因此模式“/”匹配其他注册模式不匹配的所有路径,而不仅仅是路径 ==“/”的 URL。

如果一个子树已经注册并且接收到一个命名子树根的请求没有尾部斜杠,ServeMux 将该请求重定向到子树根(添加尾部斜杠)。可以通过单独注册不带斜杠的路径来覆盖此行为。例如,注册“/images/”会导致 ServeMux 将对“/images”的请求重定向到“/images/”,除非“/images”已单独注册。

(斜体我的)

我的假设ServeMux 几乎表现得像 nginx 和/或 Apache 的 rewrite 模块的基于规则的模式匹配功能,即。 e.规则是根据它们注册的顺序进行处理的,因此我希望首先匹配/first(双关语),并且只有在没有找到匹配项时,才会匹配/下一个 em>。

但这不是文档所说的。相反,注册的顺序并没有真正的区别。 ServeMux,在我给定的场景中,因为我忘记添加尾部斜杠,将总是“回退”到 "/" 的处理程序,而不是因为匹配算法的某些错误或变态, 但因为这是 Go 开发人员编写的预期行为!换句话说,如果你有一个"/" 的处理程序,它就可以作为每个非斜杠终止子树的包罗万象。

我只是没能正确阅读文档! (或者可能回到 2017 年那段还不够清楚)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-24
    • 1970-01-01
    • 2018-12-21
    • 1970-01-01
    • 2020-12-17
    • 2013-12-17
    • 1970-01-01
    • 2012-12-25
    相关资源
    最近更新 更多