Go CGI 使用

 

Go 中包含有 CGI 包,net/http/cgi,这篇文章就是来阅读和使用这个包。关于 CGI 的参数和运行,可以看这篇文章:CGI的一些知识点

img

CGI 包阅读

cgi 包的存在就告诉我们一件事情,cgi 服务端和客户端完全可以使用 go 来写

这个包其实很简单,只有两个文件,其他都是测试程序

  • child.go
  • host.go

host.go 是可以直接宿主到 web 服务器上的代码,里面提供了对 requestresponse 的直接处理函数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. :star2:

Star This Project