在Go + FastCGI中,使用多个处理程序有意义吗?

hxzsmxv2  于 2023-02-27  发布在  Go
关注(0)|答案(2)|浏览(315)

地鼠新手在这里。请善良:-)
我在一个运行Apache + FastCGI的共享服务器上有一个账户,但我无法控制它。不过,它与Go语言的接口很流畅。我更习惯于在net/http上使用Go语言,但弄清楚如何在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配置)?还是我做错了什么?
(For为了完整起见,我应该补充一点,是的,我已经尝试了上面的几种变体,重命名Go应用程序,使用子文件夹,使用 * 几个 * 处理程序,而不仅仅是一个,等等。)
我的真实的场景实际上是一个小应用程序,它应该作为使用net/http的独立Web服务器运行 *,或者在独立模式不受支持甚至被禁止的情况下作为FastCGI应用程序运行(这是共享环境的一些提供者的情况)。由于实际处理对于任一种情况是完全相同的,唯一的区别是调用fcgi.Serve()而不是http.ListenAndServe()。但是,如果能够在FastCGI下使用具有不同处理程序的net/http包的路由能力,那就太好了。
提前感谢你的见解。即使答案是“是的,这 * 正是 * FastCGI实现在Go语言下的工作方式--只有一个处理程序!”,这仍然是有用的--这意味着我只需要围绕我自己的代码,以不同的方式做事(基本上,基于通过Form接口传递的参数创建我自己的路由器/调度器--没什么大不了的,这是可行的!)

2ic8powd

2ic8powd1#

我知道这是一个老帖子,但我自己才刚开始玩围棋和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最接近的匹配项,即/

yr9zkbsy

yr9zkbsy2#

  • 更新2023-02-24:* 我在下面的假设中完全错了。@Kodiak是对的,我只是不太明白。几年后,感谢@Hudon在下面的评论(也许还有更多的经验.... A.),我拒绝我的这个旧答案,并接受@Kodiak 's是正确的答案(事实就是如此)。

我只是为了历史的目的而保留以下几点。提醒你一下,这并不是“完全错误”;但这是基于我对传递给ServeMux的实际URL的无知。现在我知道了:)
在阅读了@Kodiak提供的答案后,我重新阅读了ServeMux的文档,并看到了这一段:
注意,由于以斜杠结尾的模式命名了一个根目录子树,因此模式“/”匹配所有未被其他注册模式匹配的路径,而不仅仅是Path ==“/"的URL。
如果子树已经注册,并且接收到命名子树根 * 而没有其尾部斜杠 * 的请求,则ServeMux将该请求重定向到子树根(添加尾部斜杠)。此行为可通过单独注册不带尾部斜杠的路径来覆盖。例如,注册“/images/”会导致ServeMux将对“/images”的请求重定向到“/images/",除非“/images”已单独注册。
(斜体为我所用)
我的“假设”是ServeMux的行为与nginx和/或Apache的rewrite模块的基于规则的模式匹配特性非常相似,即规则是根据它们注册的顺序处理的,因此我希望首先匹配/first(双关语),只有在没有找到匹配时,才匹配/
但这并不是文档所说的那样,相反,注册的顺序并没有真实的的区别;ServeMux,在我给出的场景中,因为我忘了添加一个尾部斜杠,将 * 总是 “退回”到"/"的处理程序,这不是因为匹配算法的错误或反常, 而是因为这是Go语言开发人员编写的预期行为 *!换句话说,如果您有"/"的处理程序,它充当每个非斜线终止的子树的捕获器。
我只是没能正确阅读文档!(或者也许早在2017年,这一段不够清楚)

相关问题