Go中的CGI包使用

简介:

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

CGI包阅读

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

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

child.go

host.go

 

host.go是可以直接宿主到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包使用

然后自然想到的一个问题,能不能实现

go-web服务器 + go-cgi + cgi-script

 

这个是可以做的,而且也不复杂:

代码如下:

package main
 
import(
   "net/http/cgi"
   "log"
   "net/http"
)
 
func main() {
   http.HandleFunc( "/" , func(w http.ResponseWriter, r *http.Request){
     handler := new (cgi.Handler)
     handler.Path = "/home/yejianfeng/go/gopath/src/cgi-script/"  + r.URL.Path
     log.Println(handler.Path)
     handler.Dir = "/home/yejianfeng/go/gopath/src/cgi-script/"
 
     handler.ServeHTTP(w, r)
   })
 
   log.Fatal(http.ListenAndServe( ":8989" ,nil))
}

如果你在cgi-script中有个可运行的cgi脚本,比如test.perl

那么我们就可以在浏览器中调用http://10.16.15.64:8989/test.perl

来进行脚本调用

 

然后进一步想,能不能把go代码当作是php这样的动态脚本来运行呢,这样就可以一边修改go源码,一边就可以在页面中立刻显示修改结果了。即

go-web + go-cgi + go-cgi-script?

答案同样也是可以,但是这个时候由于xx.go并非是可执行文件,只能使用go run 来进行调用。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main
 
import(
   "net/http/cgi"
   "log"
   "net/http"
)
 
func main() {
   http.HandleFunc( "/" , func(w http.ResponseWriter, r *http.Request){
     handler := new (cgi.Handler)
     handler.Path = "/home/yejianfeng/bin/go"
     script := "/home/yejianfeng/go/gopath/src/cgi-script/"  + r.URL.Path
     log.Println(handler.Path)
     handler.Dir = "/home/yejianfeng/go/gopath/src/cgi-script/"
     args := []string{ "run" , script}
     handler.Args = append(handler.Args, args...)
     handler.Env = append(handler.Env, "GOPATH=/home/yejianfeng/go/gopath" )
     handler.Env = append(handler.Env, "GOROOT=/home/yejianfeng/go/go" )
     log.Println(handler.Args)
 
     handler.ServeHTTP(w, r)
   })
 
   log.Fatal(http.ListenAndServe( ":8989" ,nil))
}

 

然后在cgi-script文件夹中建立test.go

1
2
3
4
5
6
7
8
9
10
11
12
13
package main
 
import(
   "fmt"
)
 
func init() {
   fmt. Print ( "Content-Type: text/plain;charset=utf-8\n\n" );
}
 
func main() {
   fmt.Println( "This is go test!!!!" )
}

这里的init()是必须打印出来的

然后就可以打印出页面了

Image

这时候go就像php脚本一样,如果你修改了test.go就能立刻在页面上显示出来了

 

对于第二种,当然也可以使用监控文件夹的修改等,当go项目修改后就重新build出一个可执行脚本,然后cgi的handler就修改下路由指向到这个可执行脚本。

关于监控文件的项目现在已经有很多开源的了:比如这个https://github.com/jianfengye/go-superviser

 

Ps: 文中说的例子已经加到http://go.funaio.com/pkg/net/http/cgi/ 的Example中了。

目录
相关文章
|
12天前
|
存储 JSON 监控
Viper,一个Go语言配置管理神器!
Viper 是一个功能强大的 Go 语言配置管理库,支持从多种来源读取配置,包括文件、环境变量、远程配置中心等。本文详细介绍了 Viper 的核心特性和使用方法,包括从本地 YAML 文件和 Consul 远程配置中心读取配置的示例。Viper 的多来源配置、动态配置和轻松集成特性使其成为管理复杂应用配置的理想选择。
33 2
|
11天前
|
Go 索引
go语言中的循环语句
【11月更文挑战第4天】
20 2
|
11天前
|
Go C++
go语言中的条件语句
【11月更文挑战第4天】
23 2
|
14天前
|
程序员 Go
go语言中的控制结构
【11月更文挑战第3天】
90 58
|
2天前
|
安全 Go 数据处理
Go语言中的并发编程:掌握goroutine和channel的艺术####
本文深入探讨了Go语言在并发编程领域的核心概念——goroutine与channel。不同于传统的单线程执行模式,Go通过轻量级的goroutine实现了高效的并发处理,而channel作为goroutines之间通信的桥梁,确保了数据传递的安全性与高效性。文章首先简述了goroutine的基本特性及其创建方法,随后详细解析了channel的类型、操作以及它们如何协同工作以构建健壮的并发应用。此外,还介绍了select语句在多路复用中的应用,以及如何利用WaitGroup等待一组goroutine完成。最后,通过一个实际案例展示了如何在Go中设计并实现一个简单的并发程序,旨在帮助读者理解并掌
|
2天前
|
Go 索引
go语言按字符(Rune)遍历
go语言按字符(Rune)遍历
12 3
|
5天前
|
Go API 数据库
Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
本文介绍了 Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
23 4
|
5天前
|
缓存 监控 前端开发
在 Go 语言中实现 WebSocket 实时通信的应用,包括 WebSocket 的简介、Go 语言的优势、基本实现步骤、应用案例、注意事项及性能优化策略,旨在帮助开发者构建高效稳定的实时通信系统
本文深入探讨了在 Go 语言中实现 WebSocket 实时通信的应用,包括 WebSocket 的简介、Go 语言的优势、基本实现步骤、应用案例、注意事项及性能优化策略,旨在帮助开发者构建高效稳定的实时通信系统。
35 1
|
5天前
|
中间件 Go API
Go语言中几种流行的Web框架,如Beego、Gin和Echo,分析了它们的特点、性能及适用场景,并讨论了如何根据项目需求、性能要求、团队经验和社区支持等因素选择最合适的框架
本文概述了Go语言中几种流行的Web框架,如Beego、Gin和Echo,分析了它们的特点、性能及适用场景,并讨论了如何根据项目需求、性能要求、团队经验和社区支持等因素选择最合适的框架。
21 1
|
9天前
|
Go
go语言中的continue 语句
go语言中的continue 语句
20 3