最简单的Golang CGI表单示例

时间:2017-04-29 23:06:55

标签: go cgi

我非常感谢使用表单输入提供最基本的CGI程序方面的帮助。我不想运行监听器或使用框架或做除了最基本的可能示例之外的任何事情。这只是为了让我的脚进入门,我将在以后添加铃声和口哨声。

这是一个没有表单输入的简单CGI应用程序:

package main

import "fmt"
import "os"

func main() {
        ip := os.Getenv("REMOTE_ADDR")
        fmt.Printf("Content-type: text/plain\n\n")
        fmt.Println(ip)
}

当我转到https://example.com/cgi-bin/ip

时,会打印我的IP地址

但是,以下代码会导致502错误:

package main

import (
        "fmt"
        "net/http"
        s "strings"
)

func main() {
        var r *http.Request

        fmt.Printf("Content-type: text/html\n\n")
        fmt.Println("<!DOCTYPE html>")
        fmt.Println("<title>login</title>")
        r.ParseForm()
        username := r.FormValue("username")
        password := r.FormValue("password")
        if s.Compare(password, username) == 0 {
                fmt.Println("<p>invalid username/password")
        }
}

nginx日志说:

2017/04/29 22:55:12 [错误] 45768#0:* 802上游过早关闭FastCGI stdout,同时从上游读取响应头,客户端:192.0.2.80,server:example.com,request:&# 34; POST / cgi-bin / login HTTP / 2.0&#34;,upstream:&#34; fastcgi:// unix:run / slowcgi.sock:&#34;,host:&#34; example.com&# 34;,推荐人:&#34; https://example.com/login.html&#34;

此表单的HTML是:

<!DOCTYPE html>
<title>Username and password</title>

<form action="/cgi-bin/login" method="post">
<table>
<tr><td>Username:</td><td><input type="text" name="username"></td></tr>
<tr><td>Password:</td><td><input type="password" name="password"></td></tr>
<tr><td> </td><td><input type="submit" value="Submit"></td></tr>
</table>
</form>

另一个注意事项:这是OpenBSD上的nginx,使用slowcgi(8)。自从我的玩具&#34; ip&#34;程序有效,我相信我的Go代码就是问题。

我的Go代码中出错了什么?谢谢!

编辑:我现在有以下代码,它们没有编译。我做错了什么?

package main

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

func main() {
        httpReq, err := cgi.Request()
        if err != nil {
                fmt.Fprintf(os.Stderr, err.Error())
                os.Exit(1)
        }

        r := httpReq.ParseForm()
        username := r.FormValue("username")
        password := r.FormValue("password")

        fmt.Printf("Content-type: text/html\n\n")
        fmt.Printf("<!DOCTYPE html>\n")
        fmt.Printf("<p>username: %s\n", username)
        fmt.Printf("<p>password: %s\n", password)
}

1 个答案:

答案 0 :(得分:3)

由于net/http/cgi不适合您,并且从提及FastCGI的nginx查看错误日志,您可能需要使用net/http/fcgi包。

如果您查看其文档,您可以看到您需要做更多工作才能访问该请求。

首先声明一个将用于处理请求的函数:

func myhandler(_ http.ResponseWriter, r *http.Request) {
    // handle request
}

然后将新处理程序传递给fcgi.Serve函数。

fcgi.Serve(nil, http.HandlerFunc(myhandler))

Serve有两个参数。第一个是net.Listener,如果nil传入,Serve会读取stdin的请求。第二个类型是http.Handler类型,它是myhandler函数未实现的接口,但是根据其特定的签名(func(http.ResponseWriter, *http.Request)),您可以转换myhandler使用http.HandlerFunc类型转换为http.Handler

完整示例:

package main

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

func myhandler(_ http.ResponseWriter, r *http.Request) {
    if err := r.ParseForm(); err != nil {
        fmt.Fprintf(os.Stderr, err.Error())
        os.Exit(1)
    }

    username := r.FormValue("username")
    password := r.FormValue("password")

    fmt.Printf("Content-type: text/html\n\n")
    fmt.Printf("<!DOCTYPE html>\n")
    fmt.Printf("<p>username: %s\n", username)
    fmt.Printf("<p>password: %s\n", password)
}

func main() {
    if err := fcgi.Serve(nil, http.HandlerFunc(myhandler)); err != nil {
        panic(err)
    }
}