Go 中包含有 CGI 包,net/http/cgi
,这篇文章就是来阅读和使用这个包。关于 CGI 的参数和运行,可以看这篇文章:CGI的一些知识点
CGI 包阅读
cgi 包的存在就告诉我们一件事情,cgi 服务端和客户端完全可以使用 go 来写
这个包其实很简单,只有两个文件,其他都是测试程序
- child.go
- host.go
host.go 是可以直接宿主到 web 服务器上的代码,里面提供了对 request
和 response
的直接处理函数ServerHTTP
, 当你是使用 go 的 http
包写了个 http 之后,就可以使用 ServerHTTP 对请求直接配置 上cgi,有点像 apache 中自带了 php-cgi
child.go 则是已经进入到脚本子进程中了,如果你的 CGI 脚本是 go 代码生成的可执行脚本,那么你就会有用到这个文件里面的函数了。这个文件内提供了将命令行环境(CGI请求)转换成 Go 的 http 包中的 request 的方法。
host.go是cgi的启动父程序需要用到的包,child.go是子程序需要用到的包
host.go
首先是 trailingPort
,这个变量是 cgi 服务器监听的端口号,(比如在nginx中我们一般都监听9000)
然后是 osDefaultInheritEnv
,这个 map 将各个平台的共享库默认路径列出来了。为什么设置这个变量呢?这样说,由于 CGI 服务器执行命令的时候命令查找设置参数有的是去环境变量中获取的,因此对每个命令执行需要设置一下环境变量。而在不同的平台,动态库的路径是不一样的,所以有了这么个 map。
Handler是在子程序中执行cgi脚本的。里面要注意的结构是两个Env和InheritEnv两个,一个是特别设定的环境变量,另外一个是继承的环境变量。
还有Handler中的Path,就是执行文件的路径,比如/test.php
下面就是最重要的ServeHTTP了,这个是用来回调处理HTTP请求的,它会将HTTP请求转化为CGI请求,并且执行这个cgi脚本。
在这个函数中,能看到CGI的RFC标准参数赋值,然后可以看到拼出了env之后将env作为exec.Cmd的Env来调用cgi脚本(path)。同时也看到了当body内有content的时候,会将Body作为stdin输入,然后从stdout出来的东西逐行读取,然后读取到header和body中去。
看了host.go的实现就很好理解child.go的实现了。
从Serve(handler)来看,先是使用将nginx提供的cgi请求转换成为net包中的http request和response,如果你有设置handler,就用request和response来进行处理。
后续的几个操作Write,Flush都已经是简单的buffer处理了。
CGI 包的使用
package servers
import (
"log"
"net/http"
"net/http/cgi"
"strings"
)
func StartCGI2(cgiRootDir string) {
handler := new(cgi.Handler)
//handler.Dir = cgiRootDir
//handler.Root = "/active/"
http.HandleFunc("/active/", func(w http.ResponseWriter, r *http.Request) {
log.Println("begin")
urlPath := r.URL.Path
handler.Path = cgiRootDir + urlPath
log.Println("root -> ", handler.Root)
log.Println("url path =-> ", urlPath)
handler.ServeHTTP(w, r)
})
fileServer := http.FileServer(http.Dir(cgiRootDir))
http.Handle("/", fileServer)
log.Fatal(http.ListenAndServe(":8989", nil))
}
如果 ./active/ 中有个可以运行的 cgi 脚本,比如 test.perl , 那么就可以在浏览器中调用 http://localhost/test.perl 来调用脚本。
cat active/index.asp
#!/usr/bin/env bash
echo 'Content-Type: text/html; charset=utf-8'
echo ''
echo '<html><head><title>My CGI Test</title>'
echo '<link rel="shortcut icon" href="/favicon.ico"/>'
echi '<link rel="bookmark" href="/favicon.ico"/>'
echo '<script src="/static/a.js"></script>'
echo '</head>'
echo '<body>'
echo '<h1>It works</h1>'
echo '<a href="./v2/info.sh">info</a><br />'
echo '<div>@copy 2022 北京俊茵科技</div>'
echo '</body></html>'
照猫画虎的猫:
If you like TeXt, don’t forget to give me a star.