duaj39673 2017-04-29 23:06
浏览 365

最简单的Golang CGI表单示例

I'd appreciate some help with the most basic possible CGI program with a form input. I don't want to run a listener or use a framework or do anything beyond the most basic possible example. This is just to get my feet in the door, and I will add the bells and whistles later.

Here's a simple CGI app without a form input:

package main

import "fmt"
import "os"

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

")
        fmt.Println(ip)
}

This prints my IP address when I go to https://example.com/cgi-bin/ip

However, the following code results in a 502 error:

package main

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

func main() {
        var r *http.Request

        fmt.Printf("Content-type: text/html

")
        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")
        }
}

The nginx log says:

2017/04/29 22:55:12 [error] 45768#0: *802 upstream prematurely closed FastCGI stdout while reading response header from upstream, client: 192.0.2.80, server: example.com, request: "POST /cgi-bin/login HTTP/2.0", upstream: "fastcgi://unix:run/slowcgi.sock:", host: "example.com", referrer: "https://example.com/login.html"

The HTML for this form is:

<!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>

Another note: this is nginx on OpenBSD, using slowcgi(8). Since my toy "ip" program works, I believe my Go code is the problem.

What am I doing wrong in my Go code? Thank you!

EDIT: I now have the following code, which doesn't compile. What am I doing wrong?

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

")
        fmt.Printf("<!DOCTYPE html>
")
        fmt.Printf("<p>username: %s
", username)
        fmt.Printf("<p>password: %s
", password)
}
  • 写回答

1条回答 默认 最新

  • dongyue9864 2017-04-30 22:08
    关注

    Since net/http/cgi is not working for you and looking at the error log from nginx mentioning FastCGI, you might need to use the net/http/fcgi package.

    If you look at its documentation you can see that you'll need to do a little bit more work to get access to the request.

    First declare a function that will be used to handle the requests:

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

    Then pass your new handler to the fcgi.Serve function.

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

    Serve takes two parameters. The first one is a net.Listener, if passed in as nil, Serve will read the requests from stdin. The second one, is of type http.Handler which is an interface that the myhandler function, as is, does not implement but given its specific signature (func(http.ResponseWriter, *http.Request)) you can convert myhandler to an http.Handler using the http.HandlerFunc type.

    Full example:

    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
    
    ")
        fmt.Printf("<!DOCTYPE html>
    ")
        fmt.Printf("<p>username: %s
    ", username)
        fmt.Printf("<p>password: %s
    ", password)
    }
    
    func main() {
        if err := fcgi.Serve(nil, http.HandlerFunc(myhandler)); err != nil {
            panic(err)
        }
    }
    
    评论

报告相同问题?

悬赏问题

  • ¥15 微信小程序协议怎么写
  • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?
  • ¥20 怎么用dlib库的算法识别小麦病虫害
  • ¥15 华为ensp模拟器中S5700交换机在配置过程中老是反复重启
  • ¥15 java写代码遇到问题,求帮助
  • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?
  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看