gofast

其他类别 2025-08-23

gofast

gofast是纯粹写在Golang的FastCGI“客户端”库。

内容

  • 真的做什么?
  • 为什么?
  • 如何使用?
    • 简单示例
    • 高级示例
      • 正常的PHP应用
      • 使用中间件自定义请求会话
      • FastCGI授权者
      • FastCGI过滤器
      • 汇总客户
    • 完整的例子
  • 作者
  • 贡献
  • 执照

真的做什么?

在FastCGI规范中,FastCGI系统具有2个组件: (a)Web服务器(b)应用程序服务器。 Web服务器应通过套接字将请求信息交给应用程序服务器。应用程序服务器始终倾听插座并响应套接字请求。

gofast可帮助您在此图片的Web服务器部分上编写代码。它可以帮助您将请求传递给应用程序服务器并从中接收响应。

您可能会认为gofast是“客户库”,以消费任何FastCGI应用程序服务器。

为什么?

许多受欢迎的语言(例如Python,PHP,Nodejs)具有FastCGI应用程序服务器的实现。使用gofast ,您可以简单地使用这些语言混合使用。

另外,这很有趣:-)

如何使用?

您基本上将使用Handler作为http.handler。您可以使用默认的ServeMux或其他兼容的路由器(例如Gorilla,Pat)进一步MUX。然后,您可以在此Golang HTTP服务器中使用FastCGI。

简单示例

请注意,这只是Web服务器组件。您需要在其他地方启动应用程序组件。

gofast" ) func main() { // Get fastcgi application server tcp address // from env FASTCGI_ADDR. Then configure // connection factory for the address. address := os.Getenv("FASTCGI_ADDR") connFactory := gofast .SimpleConnFactory("tcp", address) // route all requests to a single php file http.Handle("/", gofast .NewHandler( gofast .NewFileEndpoint("/var/www/html/index.php")( gofast .BasicSession), gofast .SimpleClientFactory(connFactory), )) // serve at 8080 port log.Fatal(http.ListenAndServe(":8080", nil)) } ">
 // this is a very simple fastcgi web server
package main

import (
	"log"
	"net/http"
	"os"

	"github.com/yookoala/ gofast "
)

func main () {
	// Get fastcgi application server tcp address
	// from env FASTCGI_ADDR. Then configure
	// connection factory for the address.
	address := os . Getenv ( "FASTCGI_ADDR" )
	connFactory := gofast . SimpleConnFactory ( "tcp" , address )

	// route all requests to a single php file
	http . Handle ( "/" , gofast . NewHandler (
		gofast . NewFileEndpoint ( "/var/www/html/index.php" )( gofast . BasicSession ),
		gofast . SimpleClientFactory ( connFactory ),
	))

	// serve at 8080 port
	log . Fatal ( http . ListenAndServe ( ":8080" , nil ))
}

高级示例

正常的PHP应用

要服务普通的PHP应用程序,您需要:

  1. 从文件系统服务静态资产;和
  2. 仅使用相关的PHP文件服务路径。
代码
gofast" ) func main() { // Get fastcgi application server tcp address // from env FASTCGI_ADDR. Then configure // connection factory for the address. address := os.Getenv("FASTCGI_ADDR") connFactory := gofast .SimpleConnFactory("tcp", address) // handles static assets in the assets folder http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.FileSystem(http.Dir("/var/www/html/assets"))))) // route all requests to relevant PHP file http.Handle("/", gofast .NewHandler( gofast .NewPHPFS("/var/www/html")( gofast .BasicSession), gofast .SimpleClientFactory(connFactory), )) // serve at 8080 port log.Fatal(http.ListenAndServe(":8080", nil)) } ">
 package main

import (
	"fmt"
	"net/http"
	"os"

	"github.com/yookoala/ gofast "
)

func main () {
	// Get fastcgi application server tcp address
	// from env FASTCGI_ADDR. Then configure
	// connection factory for the address.
	address := os . Getenv ( "FASTCGI_ADDR" )
	connFactory := gofast . SimpleConnFactory ( "tcp" , address )

	// handles static assets in the assets folder
	http . Handle ( "/assets/" ,
		http . StripPrefix ( "/assets/" ,
			http . FileServer ( http . FileSystem ( http . Dir ( "/var/www/html/assets" )))))

	// route all requests to relevant PHP file
	http . Handle ( "/" , gofast . NewHandler (
		gofast . NewPHPFS ( "/var/www/html" )( gofast . BasicSession ),
		gofast . SimpleClientFactory ( connFactory ),
	))

	// serve at 8080 port
	log . Fatal ( http . ListenAndServe ( ":8080" , nil ))
}

使用中间件自定义请求会话

每个Web服务器请求将导致gofast 。并且每个gofast .Request将首先通过SessionHandler运行,然后将gofast .client的Do()方法交给DO()方法。

默认的gofast .Basicsession实施无济于事。图书馆的功能像gofast .Newphpfs, gofast .newfileendpoint是gofast .Middleware实现,它们是较低级别的中间件链。

因此,您可以通过实现gofast .Middleware自定义自己的会话。

代码
gofast" ) func main() { // Get fastcgi application server tcp address // from env FASTCGI_ADDR. Then configure // connection factory for the address. address := os.Getenv("FASTCGI_ADDR") connFactory := gofast .SimpleConnFactory("tcp", address) // a custom authentication handler customAuth := func(inner gofast .SessionHandler) gofast .SessionHandler { return func(client gofast .Client, req * gofast .Request) (* gofast .ResponsePipe, error) { user, err := someCustomAuth( req.Raw.Header.Get("Authorization")) if err != nil { // if login not success return nil, err } // set REMOTE_USER accordingly req.Params["REMOTE_USER"] = user // run inner session handler return inner(client, req) } } // session handler sess := gofast .Chain( customAuth, // maps REMOTE_USER gofast .BasicParamsMap, // maps common CGI parameters gofast .MapHeader, // maps header fields into HTTP_* parameters gofast .MapRemoteHost, // maps REMOTE_HOST )( gofast .BasicSession) // route all requests to a single php file http.Handle("/", gofast .NewHandler( gofast .NewFileEndpoint("/var/www/html/index.php")(sess), gofast .SimpleClientFactory(connFactory), )) // serve at 8080 port log.Fatal(http.ListenAndServe(":8080", nil)) } ">
 package main

import (
	"fmt"
	"net/http"
	"os"

	"github.com/yookoala/ gofast "
)

func main () {
	// Get fastcgi application server tcp address
	// from env FASTCGI_ADDR. Then configure
	// connection factory for the address.
	address := os . Getenv ( "FASTCGI_ADDR" )
	connFactory := gofast . SimpleConnFactory ( "tcp" , address )

	// a custom authentication handler
	customAuth := func ( inner gofast . SessionHandler ) gofast . SessionHandler {
		return func ( client gofast . Client , req * gofast . Request ) ( * gofast . ResponsePipe , error ) {
			user , err := someCustomAuth (
				req . Raw . Header . Get ( "Authorization" ))
			if err != nil {
				// if login not success
				return nil , err
			}
			// set REMOTE_USER accordingly
			req . Params [ "REMOTE_USER" ] = user
			// run inner session handler
			return inner ( client , req )
		}
	}

	// session handler
	sess := gofast . Chain (
		customAuth ,            // maps REMOTE_USER
		gofast . BasicParamsMap , // maps common CGI parameters
		gofast . MapHeader ,      // maps header fields into HTTP_* parameters
		gofast . MapRemoteHost ,  // maps REMOTE_HOST
	)( gofast . BasicSession )

	// route all requests to a single php file
	http . Handle ( "/" , gofast . NewHandler (
		gofast . NewFileEndpoint ( "/var/www/html/index.php" )( sess ),
		gofast . SimpleClientFactory ( connFactory ),
	))

	// serve at 8080 port
	log . Fatal ( http . ListenAndServe ( ":8080" , nil ))
}

FastCGI授权者

FASTCGI指定了授权使用“授权器应用程序”的HTTP请求的授权者角色。与通常的FASTCGI应用程序(IE响应者)不同,它仅进行授权检查。

规格摘要

在实际服务HTTP请求之前,Web服务器可以将正常的FASTCGI请求格式化为仅使用FastCGI参数( FCGI_PARAMS流)的授权器应用程序。此应用程序负责确定请求是否正确验证并授权该请求。

如果有效,

  • 授权器应用程序应使用HTTP状态200 (确定)响应。

  • 它可以通过将Variable-SOME-HEADER头标头字段添加到其对Web服务器的响应中,从而将其他变量(例如SOME-HEADER )添加到子序列请求中。

  • Web服务器将从旧的请求创建一个新的HTTP请求,并附加附加标题变量(例如Some-Header ),然后将修改后的请求发送到子任务应用程序。

如果无效,

  • 授权器应用程序应以HTTP状态为不200 http状态响应,并且要显示登录失败的内容。

  • Web服务器将跳过响应者,直接显示授权者的回应。

代码
gofast" ) func myApp() http.Handler { // ... any normal http.Handler, using gofast or not return h } func main() { address := os.Getenv("FASTCGI_ADDR") connFactory := gofast .SimpleConnFactory("tcp", address) clientFactory := gofast .SimpleClientFactory(connFactory) // authorization with php authSess := gofast .Chain( gofast .NewAuthPrepare(), gofast .NewFileEndpoint("/var/www/html/authorization.php"), )( gofast .BasicSession) authorizer := gofast .NewAuthorizer( authSess, gofast .SimpleConnFactory(network, address) ) // wrap the actual app http.Handle("/", authorizer.Wrap(myApp())) // serve at 8080 port log.Fatal(http.ListenAndServe(":8080", nil)) } ">
 package main

import (
	"net/http"
	"time"

	"github.com/yookoala/ gofast "
)

func myApp () http. Handler {
  // ... any normal http.Handler, using gofast or not
	return h
}

func main () {
	address := os . Getenv ( "FASTCGI_ADDR" )
	connFactory := gofast . SimpleConnFactory ( "tcp" , address )
	clientFactory := gofast . SimpleClientFactory ( connFactory )

	// authorization with php
	authSess := gofast . Chain (
		gofast . NewAuthPrepare (),
		gofast . NewFileEndpoint ( "/var/www/html/authorization.php" ),
	)( gofast . BasicSession )
	authorizer := gofast . NewAuthorizer (
		authSess ,
		gofast . SimpleConnFactory ( network , address )
	)

	// wrap the actual app
	http . Handle ( "/" , authorizer . Wrap ( myApp ()))

	// serve at 8080 port
	log . Fatal ( http . ListenAndServe ( ":8080" , nil ))
}

FastCGI过滤器

FastCGI在发送之前指定了过滤Web服务器资产的过滤角色。与通常的FastCGI应用程序(IE响应者)不同,请求的数据位于Web服务器端。因此,当要求时,Web服务器将将这些数据传递给应用程序。

代码
gofast" ) func main() { address := os.Getenv("FASTCGI_ADDR") connFactory := gofast .SimpleConnFactory("tcp", address) clientFactory := gofast .SimpleClientFactory(connFactory) // Note: The local file system "/var/www/html/" only need to be // local to web server. No need for the FastCGI application to access // it directly. connFactory := gofast .SimpleConnFactory(network, address) http.Handle("/", gofast .NewHandler( gofast .NewFilterLocalFS("/var/www/html/")( gofast .BasicSession), clientFactory, )) // serve at 8080 port log.Fatal(http.ListenAndServe(":8080", nil)) } ">
 package main

import (
	"net/http"
	"time"

	"github.com/yookoala/ gofast "
)

func main () {
	address := os . Getenv ( "FASTCGI_ADDR" )
	connFactory := gofast . SimpleConnFactory ( "tcp" , address )
	clientFactory := gofast . SimpleClientFactory ( connFactory )

	// Note: The local file system "/var/www/html/" only need to be
	// local to web server. No need for the FastCGI application to access
	// it directly.
	connFactory := gofast . SimpleConnFactory ( network , address )
	http . Handle ( "/" , gofast . NewHandler (
		gofast . NewFilterLocalFS ( "/var/www/html/" )( gofast . BasicSession ),
		clientFactory ,
	))

	// serve at 8080 port
	log . Fatal ( http . ListenAndServe ( ":8080" , nil ))
}

汇总客户

为了拥有更好,更受控的扩展属性,您可以使用客户室扩展客户端。

代码
gofast" ) func main() { // Get fastcgi application server tcp address // from env FASTCGI_ADDR. Then configure // connection factory for the address. address := os.Getenv("FASTCGI_ADDR") connFactory := gofast .SimpleConnFactory("tcp", address) // handles static assets in the assets folder http.Handle("/assets/", http.StripPrefix("/assets/", http.FileSystem(http.Dir("/var/www/html/assets")))) // handle all scripts in document root // extra pooling layer pool := gofast .NewClientPool( gofast .SimpleClientFactory(connFactory), 10, // buffer size for pre-created client-connection 30*time.Second, // life span of a client before expire ) http.Handle("/", gofast .NewHandler( gofast .NewPHPFS("/var/www/html")( gofast .BasicSession), pool.CreateClient, )) // serve at 8080 port log.Fatal(http.ListenAndServe(":8080", nil)) } ">
 package main

import (
	"fmt"
	"net/http"
	"os"

	"github.com/yookoala/ gofast "
)

func main () {
	// Get fastcgi application server tcp address
	// from env FASTCGI_ADDR. Then configure
	// connection factory for the address.
	address := os . Getenv ( "FASTCGI_ADDR" )
	connFactory := gofast . SimpleConnFactory ( "tcp" , address )

	// handles static assets in the assets folder
	http . Handle ( "/assets/" ,
		http . StripPrefix ( "/assets/" ,
			http . FileSystem ( http . Dir ( "/var/www/html/assets" ))))

	// handle all scripts in document root
	// extra pooling layer
	pool := gofast . NewClientPool (
		gofast . SimpleClientFactory ( connFactory ),
		10 , // buffer size for pre-created client-connection
		30 * time . Second , // life span of a client before expire
	)
	http . Handle ( "/" , gofast . NewHandler (
		gofast . NewPHPFS ( "/var/www/html" )( gofast . BasicSession ),
		pool . CreateClient ,
	))

	// serve at 8080 port
	log . Fatal ( http . ListenAndServe ( ":8080" , nil ))
}

完整的例子

请参阅示例用法:

  • php
  • python3
  • nodejs

作者

该图书馆由考拉·杨(Koala Yeung)撰写。

贡献

欢迎您为这个图书馆做出贡献。

要报告错误,请使用问题跟踪器。

要修复现有错误或实施新功能,请:

  1. 检查问题跟踪器并提取现有讨论请求。
  2. 如果没有,请打开一个新问题进行讨论。
  3. 写测试。
  4. 打开引用该问题的拉请请求。
  5. 玩得开心 :-)

执照

该库是根据BSD式许可发布的。请在此存储库中找到许可证文件

下载源码

通过命令行克隆项目:

git clone https://github.com/yookoala/gofast.git