英文:
Go Web App: How to route PHP scripts to PHP-FPM from Golang
问题
我有一个主要的网站和许多小型网站。目前我正在使用Nginx和PHP来运行它们。我的计划是放弃这两个,用Go构建一个单一的Web应用程序来提供所有服务,这样有望减少负载和内存使用(特别是因为一些页面的计算量很大)。
我的问题是,如果我尝试将很少使用的PHPBB论坛转移到Go上,那将是一种严重的浪费时间。所以我希望主要的网站由Go Web应用程序提供服务,但其他一些仍然使用PHP的网站可以保持不变。
我的问题是:我能否使用Go Web应用程序将对PHP脚本的请求路由到PHP-FPM?
我希望能够摒弃Nginx,Web应用程序将处理所有的传入流量,并直接从自己的代码中提供主要网站的服务,但对于仍然使用PHP的较不重要的网站,可以通过Go应用程序将这些请求路由到PHP-FPM(包括所有的请求信息,如cookies、POST变量等)。
有什么想法吗?
英文:
I have one main web site and numerous small web sites. I'm currently using Nginx & PHP for all of this. My plan is to do away with both and build a single web app in Go that will serve everything, which will hopefully reduce load and memory (especially since some of the pages are very computationally heavy.)
My issue is that it would be a serious waste of time for me to try to port things like rarely used PHPBB forums to Go. So I'd like to have the main web site all served from the Go web app, but some of the other sites can remain as PHP.
My question is: can I use the Go web app to route requests for PHP scripts to PHP-FPM?
I would like it so that I can do away with Nginx, the web app will handle all of the incoming traffic and serve the main site directly from its own code, but for less important sites that are still in PHP these can be served by the Go app routing these requests to PHP-FPM (along with all the full request info including cookies, POST vars, etc.)
Any ideas?
答案1
得分: 3
我意识到这是一个古老的帖子,但是我想给出我的答案,因为在遇到类似问题后,我不得不为自己进行研究。
简而言之,我建议通过HTTP代理到Nginx,然后让Nginx与PHP-FPM通信,不是因为Nginx更好、更快、更亮眼之类的原因,而是因为这条代码路径经过了数倍的测试和维护,而且缺点很小。
有两种明显的方法:
A) 使用Nginx并通过Go代理请求到PHP。可以使用httputil来实现,就像@fabrizioM的答案中所描述的那样,它实际上是通过HTTP将请求代理到Nginx,然后将其转换为FastCGI并调用PHP-FPM。
B) 使用FastCGI协议的实现直接从Go调用PHP-FPM。我没有尝试过这种方法,但是有很多Go库可以实现,包括:
- https://github.com/tomasen/fcgi_client
- https://github.com/yookoala/gofast
- https://gist.github.com/wofeiwo/3727055
- 还有其他的...
注意:我意识到这些库可能在问题提出时还不存在。
上述第一个库在撰写本文时有21个星。
在我看来,虽然Nginx是一个很棒的Web服务器,但是与在Go中提供静态文件相比,几乎没有什么好处。然而,在这里使用Nginx的一个重要优点是它提供了稳定和可维护的FastCGI代码。显然,在Go中通过FastCGI调用并不是一种非常流行的方法,我不知道我有多少信任这种实现。另一方面,有大量的PHP开发人员发誓要使用Nginx+PHP-FPM,它经过了充分的测试和维护。
在使用HTTP进行代理时,还有一些其他好处,例如在本地开发期间,当您将Go进程的请求转发到您的PHP服务器时,它更有可能正常工作。这使得您可以轻松地在Go应用程序上进行开发,而无需运行所有PHP相关的本地副本,同时仍然能够看到所有功能。
因此,虽然这两种方法都可行,但我的建议是仅包含Nginx,因为它是一个更好支持的代码路径,您的请求通过它流动,具有一些实际的本地开发优势,而性能损失可以忽略不计。我认为这些论点比“Nginx在提供静态文件方面很棒”或“内存使用低”等论点更有说服力。
英文:
I realize this is an ancient post, but here's my answer since I've had to research this for myself after running into essentially the same issue.
TL;DR I suggest proxying to Nginx via HTTP and letting it talk to PHP-FPM - not because Nginx is better or faster or shinier or whatever, but because this code path is orders of magnitude more well tested and maintained and the disadvantages are minimal.
Two obvious approaches:
A) Use Nginx and proxy request through go to PHP. This can be done with httputil as described in @fabrizioM's answer, and is essentially proxying the request via HTTP to Nginx which then converts it to FastCGI and calls PHP-FPM.
B) Use an implementation of the FastCGI protocol to call to PHP-FPM directly from Go. I haven't tried this, but there are a number of Go libraries out there which purport to do this, including:
- https://github.com/tomasen/fcgi_client
- https://github.com/yookoala/gofast
- https://gist.github.com/wofeiwo/3727055
- And more...
n.b. I realize some of these probably didn't exist with the question was asked.
The first one above has 21 stars as of this writing.
IMO, while Nginx is a great webserver, there is little to gain from it over serving static files in Go. However, there is one big thing you gain by using Nginx here and it is the stability and maintenance of that FastCGI code. Clearly calling via FastCGI in Go is not an extremely popular approach, and I don't know how much I trust the implementation. On the other hand, there are bazillions of PHP devs out there who swear by Nginx+PHP-FPM and it is well tested and maintained.
There are some other nice perks when using HTTP for proxying, e.g. it's more likely to work correctly when you, during local development, forward requests from your Go process over the Internet to wherever your PHP server is. This makes it easy to hack away on your Go app without having to run a local copy of all of the PHP stuff and yet still be able to see everything functional.
So while both approaches are viable, my suggestion is to include Nginx solely because it is a much better supported code path that your requests flow through, has some practical local dev advantages and the performance loss is negligible. I think those are much stronger arguments than the "Nginx is great at serving static files" or "has low memory usage", etc. arguments.
答案2
得分: 2
PHP-FPM正在监听一个Unix套接字。因此,您可以使用net.Dial
方法简单地连接到其Unix套接字:
conn, err := net.Dial("unix", "", "/path/to/php-fpm.sock")
然后在生成的连接上写入所需内容。您可以使用net.Pipe
方法,该方法将需要使用net
包来处理连接(或劫持更经典的http
服务器的连接)。
话虽如此,我仍然建议不要使用Go来处理这个问题:Nginx非常高效、快速,内存使用率低,它会比您做得更好。您应该(在我看来)将每个要转换为Go的应用程序进行移植,然后使用Nginx作为反向代理。如果您追求性能,可以使用Unix套接字在Nginx和应用程序之间进行通信,因为它比在TCP端口上进行监听更快。
英文:
PHP-FPM is listening on an unix socket. So you can simply connect to its unix socket using the net.Dial
method:
conn, err:= net.Dial("unix","", "/path/to/php-fpm.sock")
then write what you need on the resulting connection. You may use the net.Pipe
method, which will require use the net
package for connection handling (or hijacking those of a more classic http
server).
That said, I would however advice against handling this with go: nginx is highly efficient, fast, has a low memory usage, and will do this job far better than you. What you should do (IMHO) is to port each application you want to go, then use nginx as a reverse proxy. If you're after performance, you can use unix socket for communication between nginx and apps, as it will be faster than listening on a TCP port.
答案3
得分: 0
要重定向到另一个URL,您可以使用httputil.HostReverseProxy
。
origin := "http://php.website.com"
originUrl, err := url.Parse(origin)
if err != nil {
log.Fatal(err)
}
proxy := httputil.NewSingleHostReverseProxy(originUrl)
prev := proxy.Director
proxy.Director = func(req *http.Request) {
prev(req)
req.Host = originUrl.Host
}
http.HandleFunc("/php", proxy.ServeHTTP)
要重定向到另一个URL,您可以使用httputil.HostReverseProxy
。
origin := "http://php.website.com"
originUrl, err := url.Parse(origin)
if err != nil {
log.Fatal(err)
}
proxy := httputil.NewSingleHostReverseProxy(originUrl)
prev := proxy.Director
proxy.Director = func(req *http.Request) {
prev(req)
req.Host = originUrl.Host
}
http.HandleFunc("/php", proxy.ServeHTTP)
英文:
To redirect to another url you can use httputil.HostReverseProxy
origin := "http://php.website.com"
originUrl, err := url.Parse(origin)
if err != nil {
log.Fatal(err)
}
proxy := httputil.NewSingleHostReverseProxy(originUrl)
prev := proxy.Director
proxy.Director = func(req *http.Request) {
prev(req)
req.Host = originUrl.Host
}
http.HandleFunc("/php", proxy.ServeHTTP)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论