在 Go + FastCGI 中,使用多个处理程序有意义吗?
In Go + FastCGI, does it make any sense to use multiple handlers?
这里是 Gopher 新手。请善待:-)
我有一个设置,我在共享服务器上有一个帐户,运行s 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 代码是 运行 来自 URL 之类的 http://my.shared.web.server/go-fcgi-test.fcgi
。为了简单起见,我省略了大部分实际处理——但这与提取表单参数、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 应用程序的整个路径。
我在 Web 上找到的所有使用 FastCGI 类似框架的示例仅显示 一个 处理程序。这是 FastCGI 包本身的限制吗? FastCGI 协议的限制(但为什么整个路径都正确发送?)?在施加此限制的 Apache 配置上做了什么(记住,我不能触及 Apache 配置)?还是我做错了什么?
(为了完整起见,我应该补充一点,是的,我已经尝试了上述的几种变体,重命名 Go 应用程序,使用子文件夹,使用 几个 处理程序和不只是一个,等等)
我的真实场景实际上是一个小型应用程序,它应该 运行 作为独立的 Web 服务器使用 net/http
或 作为FastCGI 应用程序在单机模型不被支持甚至被禁止的情况下(某些共享环境提供商就是这种情况)。由于这两种情况的实际处理完全相同,唯一的区别是调用 fcgi.Serve()
而不是 http.ListenAndServe()
。但是,如果能够在 FastCGI 下使用具有不同处理程序的 net/http
包的路由功能,那就太好了。
提前感谢您的任何见解。即使答案是“是的,这就是 确切地 FastCGI 实现在 Go 下的工作方式——只有一个处理程序!”这仍然有用——这意味着我只需要解决我自己的代码并以不同的方式做事(基本上,根据通过 Form 接口传递的参数创建我自己的 router/dispatcher——没什么大不了的,这是可行的!)
我意识到这是一个老问题 post,但我自己刚开始使用 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
的匹配项,即 /
.
看完@Kodiak 提供的答案后,我重新阅读了 documentation for ServeMux 并看到了这段话:
Note that since a pattern ending in a slash names a rooted subtree, the pattern "/" matches all paths not matched by other registered patterns, not just the URL with Path == "/".
If a subtree has been registered and a request is received naming the subtree root without its trailing slash, ServeMux redirects that request to the subtree root (adding the trailing slash). This behavior can be overridden with a separate registration for the path without the trailing slash. For example, registering "/images/" causes ServeMux to redirect a request for "/images" to "/images/", unless "/images" has been registered separately.
(斜体是我的)
我的 假设 是 ServeMux
与 nginx
and/or Apache [=12] 的基于规则的模式匹配功能非常相似=] 模块,我。 e.规则根据它们注册的顺序进行处理,因此我期望 /first
会首先匹配(双关语意),只有在没有找到匹配项时,才会匹配 /
下一个.
但这不是文档所说的。相反,注册的顺序并没有真正的区别。 ServeMux
,在我给定的场景中,因为我忘记添加尾部斜线,将 always 'fall back' 到 "/"
的处理程序,而不是因为一些错误或匹配算法的变态,但因为这是 Go 开发人员编码的预期行为!换句话说,如果您有一个 "/"
的处理程序,它可以作为每个非斜杠终止子树的包罗万象。
我只是没有正确阅读文档! (或者也许在 2017 年那段话还不够清楚)
这里是 Gopher 新手。请善待:-)
我有一个设置,我在共享服务器上有一个帐户,运行s 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 代码是 运行 来自 URL 之类的 http://my.shared.web.server/go-fcgi-test.fcgi
。为了简单起见,我省略了大部分实际处理——但这与提取表单参数、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 应用程序的整个路径。
我在 Web 上找到的所有使用 FastCGI 类似框架的示例仅显示 一个 处理程序。这是 FastCGI 包本身的限制吗? FastCGI 协议的限制(但为什么整个路径都正确发送?)?在施加此限制的 Apache 配置上做了什么(记住,我不能触及 Apache 配置)?还是我做错了什么?
(为了完整起见,我应该补充一点,是的,我已经尝试了上述的几种变体,重命名 Go 应用程序,使用子文件夹,使用 几个 处理程序和不只是一个,等等)
我的真实场景实际上是一个小型应用程序,它应该 运行 作为独立的 Web 服务器使用 net/http
或 作为FastCGI 应用程序在单机模型不被支持甚至被禁止的情况下(某些共享环境提供商就是这种情况)。由于这两种情况的实际处理完全相同,唯一的区别是调用 fcgi.Serve()
而不是 http.ListenAndServe()
。但是,如果能够在 FastCGI 下使用具有不同处理程序的 net/http
包的路由功能,那就太好了。
提前感谢您的任何见解。即使答案是“是的,这就是 确切地 FastCGI 实现在 Go 下的工作方式——只有一个处理程序!”这仍然有用——这意味着我只需要解决我自己的代码并以不同的方式做事(基本上,根据通过 Form 接口传递的参数创建我自己的 router/dispatcher——没什么大不了的,这是可行的!)
我意识到这是一个老问题 post,但我自己刚开始使用 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
的匹配项,即 /
.
看完@Kodiak 提供的答案后,我重新阅读了 documentation for ServeMux 并看到了这段话:
Note that since a pattern ending in a slash names a rooted subtree, the pattern "/" matches all paths not matched by other registered patterns, not just the URL with Path == "/".
If a subtree has been registered and a request is received naming the subtree root without its trailing slash, ServeMux redirects that request to the subtree root (adding the trailing slash). This behavior can be overridden with a separate registration for the path without the trailing slash. For example, registering "/images/" causes ServeMux to redirect a request for "/images" to "/images/", unless "/images" has been registered separately.
(斜体是我的)
我的 假设 是 ServeMux
与 nginx
and/or Apache [=12] 的基于规则的模式匹配功能非常相似=] 模块,我。 e.规则根据它们注册的顺序进行处理,因此我期望 /first
会首先匹配(双关语意),只有在没有找到匹配项时,才会匹配 /
下一个.
但这不是文档所说的。相反,注册的顺序并没有真正的区别。 ServeMux
,在我给定的场景中,因为我忘记添加尾部斜线,将 always 'fall back' 到 "/"
的处理程序,而不是因为一些错误或匹配算法的变态,但因为这是 Go 开发人员编码的预期行为!换句话说,如果您有一个 "/"
的处理程序,它可以作为每个非斜杠终止子树的包罗万象。
我只是没有正确阅读文档! (或者也许在 2017 年那段话还不够清楚)