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中了。





本文转自轩脉刃博客园博客,原文链接:http://www.cnblogs.com/yjf512/archive/2012/12/25/2831891.html,如需转载请自行联系原作者

相关文章
|
4月前
|
Go 开发者
Go语言包的组织与导入 -《Go语言实战指南》
本章详细介绍了Go语言中的包(Package)概念及其使用方法。包是实现代码模块化、复用性和可维护性的核心单位,内容涵盖包的基本定义、命名规则、组织结构以及导入方式。通过示例说明了如何创建和调用包,并深入讲解了`go.mod`文件对包路径的管理。此外,还提供了多种导入技巧,如别名导入、匿名导入等,帮助开发者优化代码结构与可读性。最后以表格形式总结了关键点,便于快速回顾和应用。
214 61
|
16天前
|
Java 编译器 Go
【Golang】(1)Go的运行流程步骤与包的概念
初次上手Go语言!先来了解它的运行流程吧! 在Go中对包的概念又有怎样不同的见解呢?
54 4
|
3月前
|
JSON 中间件 Go
Go语言实战指南 —— Go中的反射机制:reflect 包使用
Go语言中的反射机制通过`reflect`包实现,允许程序在运行时动态检查变量类型、获取或设置值、调用方法等。它适用于初中级开发者深入理解Go的动态能力,帮助构建通用工具、中间件和ORM系统等。
266 63
|
2月前
|
缓存 监控 安全
告别缓存击穿!Go 语言中的防并发神器:singleflight 包深度解析
在高并发场景中,多个请求同时访问同一资源易导致缓存击穿、数据库压力过大。Go 语言提供的 `singleflight` 包可将相同 key 的请求合并,仅执行一次实际操作,其余请求共享结果,有效降低系统负载。本文详解其原理、实现及典型应用场景,并附示例代码,助你掌握高并发优化技巧。
250 0
|
5月前
|
Go 持续交付 开发者
Go语言包与模块(module)的基本使用-《Go语言实战指南》
本章深入讲解Go语言中的包(Package)和模块(Module)概念。包是代码组织的最小单位,每个`.go`文件属于一个包,通过`import`实现复用;主程序包需命名为`main`。模块是Go 1.11引入的依赖管理机制,支持自动版本管理和私有/远程仓库,无需依赖GOPATH。通过实际示例,如自定义包`mathutil`和第三方模块`gin`的引入,展示其使用方法。常用命令包括`go mod init`、`go mod tidy`等,帮助开发者高效管理项目依赖。最后总结,包负责功能划分,模块实现现代化依赖管理,提升团队协作效率。
233 15
|
9月前
|
Go 数据库
Go语言中的包(package)是如何组织的?
在Go语言中,包是代码组织和管理的基本单元,用于集合相关函数、类型和变量,便于复用和维护。包通过目录结构、文件命名、初始化函数(`init`)及导出规则来管理命名空间和依赖关系。合理的包组织能提高代码的可读性、可维护性和可复用性,减少耦合度。例如,`stringutils`包提供字符串处理函数,主程序导入使用这些函数,使代码结构清晰易懂。
329 11
|
10月前
|
Linux Go iOS开发
怎么禁用 vscode 中点击 go 包名时自动打开浏览器跳转到 pkg.go.dev
本文介绍了如何在 VSCode 中禁用点击 Go 包名时自动打开浏览器跳转到 pkg.go.dev 的功能。通过将 gopls 的 `ui.navigation.importShortcut` 设置为 "Definition",可以实现仅跳转到定义处而不打开链接。具体操作步骤包括:打开设置、搜索 gopls、编辑 settings.json 文件并保存更改,最后重启 VSCode 使设置生效。
384 8
怎么禁用 vscode 中点击 go 包名时自动打开浏览器跳转到 pkg.go.dev
|
11月前
|
Go 索引
go语言使用strings包
go语言使用strings包
245 3
|
11月前
|
编译器 Go 开发者
go语言中导入相关包
【11月更文挑战第1天】
167 3
|
存储 Go 数据库
Go语言Context包源码学习
【10月更文挑战第21天】Go 语言中的 `context` 包用于在函数调用链中传递请求上下文信息,支持请求的取消、超时和截止时间管理。其核心接口 `Context` 定义了 `Deadline`、`Done`、`Err` 和 `Value` 方法,分别用于处理截止时间、取消信号、错误信息和键值对数据。包内提供了 `emptyCtx`、`cancelCtx`、`timerCtx` 和 `valueCtx` 四种实现类型,满足不同场景需求。示例代码展示了如何使用带有超时功能的上下文进行任务管理和取消。
112 0

热门文章

最新文章