Home>

I don't know how to read the POST requested data with Go.

It is common to useParseForm ()method of

* http.Request, but the followingnet/httppackage I don't know how to handle it properly.

I want to tell me

I would like to know how to get POST request data without usingnet/httppackage.

Implementation

https://github.com/GoesToEleven/GolangTraining/blob/master/27_code-in-process/42_HTTP/02_http-server/i05_not-writing_error-in-code/main.go

The following code is an example. Same as the URL listed above.

package main
import (
    "bufio"
    "fmt"
    "io"
    "log"
    "net"
    "strconv"
    "strings"
)
func handleConn (conn net.Conn) {
    defer conn.Close ()
    scanner: = bufio.NewScanner (conn)
    i: = 0
    headers: = map [string] string {}
    var url, method string
    for scanner.Scan () {
        ln: = scanner.Text ()
        fmt.Println (ln)
        if i == 0 {
            fs: = strings.Fields (ln)
            method: = fs [0]
            url = fs [1]
            fmt.Println ("METHOD", method)
            fmt.Println ("URL", url)
        } else {
            // in headers now
            // when line is empty, header is done
            if ln == "" {
                break
            }
            fs: = strings.SplitN (ln, ":", 2)
            headers [fs [0]] = fs [1]
        }
        i ++
    }
    // parse body
    // This is the point
    if method == "POST" || method == "PUT" {
        amt, _: = strconv.Atoi (headers ["Content-Length"])
        buf: = make ([] byte, amt)
        // Just ReadFull cannot read the data
        io.ReadFull (conn, buf)
        // in buf we will have the POST content
        fmt.Println ("BODY:", string (buf))
    }
    // So far
    // response
    body: = `
<! DOCTYPE html>
<html lang = "en">
<head>
    <meta charset = "UTF-8">
    <title></title>
</head>
<body>
    <form method = "POST">
        <input type = "text" name = "key" value = "">
        <input type = "submit">
    </form>
</body>
</html>
    `
    io.WriteString (conn, "HTTP/1.1 200 OK \ r \ n")
    fmt.Fprintf (conn, "Content-Length:% d \ r \ n", len (body))
    io.WriteString (conn, "\ r \ n")
    io.WriteString (conn, body)
}
func main () {
    server, err: = net.Listen ("tcp", ": 9000")
    if err! = nil {
        log.Fatalln (err.Error ())
    }
    defer server.Close ()
    for {
        conn, err: = server.Accept ()
        if err! = nil {
            log.Fatalln (err.Error ())
        }
        go handleConn (conn)
    }
}
  • Client POST request

At this time, assume that the client curl sends a POST request as follows.

curl -v http: // localhost: 9000 -X POST -d "Sample message."
  • Messages output to the server

However, the server cannot read the data sent in the POST request as follows.

POST/HTTP/1.1
METHOD POST
URL /
Host: localhost: 9000
User-Agent: curl/7.55.1
Accept: */*
Content-Length: 4
Content-Type: application/x-www-form-urlencoded

"BODY:": Sample message.is supposed to be displayed .

  • Answer # 1

    The reason for writing without using the standard library is assumed to be for learning purposes.

    First, modify the error value of the return value of "io.ReadFull" to check. If it is not nil, add the contents.
    The next line of "io.ReadFull" may not be executed.

    Check if the process proceeds after io.ReadFull,
    Please tell me the contents of the return value error.

    The reason why the next line of "io.ReadFull" may not be executed is
    Since HTTP1.1, a request with the Connection header omitted omits the connection.
    HTTP1.1 connection specification (MDN)

    You may want to add curl's "-H` Connection: close '".

    Additional

    I modified the code to work. The net/textproto Reader does not read more than necessary, so it is suitable for this purpose.

    package main
    import (
        "bufio"
        "fmt"
        "io"
        "log"
        "net"
        "net/textproto"
        "strconv"
        "strings"
    )
    func handleConn (conn net.Conn) {
        defer conn.Close ()
        reader: = bufio.NewReader (conn)
        scanner: = textproto.NewReader (reader)
        i: = 0
        headers: = map [string] string {}
        var url, method string
        for {
            ln, err: = scanner.ReadLine ()
            if err! = nil {
                log.Println (err)
                return
            }
            if i == 0 {
                fs: = strings.Fields (ln)
                method = fs [0]
                url = fs [1]
                fmt.Println ("METHOD", method)
                fmt.Println ("URL", url)
            } else {
                // in headers now
                // when line is empty, header is done
                if ln == "" {
                    break
                }
                fs: = strings.SplitN (ln, ":", 2)
                headers [fs [0]] = fs [1]
            }
            i ++
        }
        // parse body
        // This is the point
        if method == "POST" || method == "PUT" {
            amt, _: = strconv.Atoi (headers ["Content-Length"])
            buf: = make ([] byte, amt)
            // Just ReadFull cannot read the data
            _, err: = io.ReadFull (reader, buf)
            if err! = nil {
                fmt.Println ("error:", err)
            }
            // in buf we will have the POST content
            fmt.Println ("BODY:", string (buf))
        }
        // So far
        // response
        body: = `
    
    
    
        
        
    
    
        
                          
        `     io.WriteString (conn, "HTTP/1.1 200 OK \ r \ n")     fmt.Fprintf (conn, "Content-Length:% d \ r \ n", len (body))     io.WriteString (conn, "\ r \ n")     io.WriteString (conn, body) } func main () {     server, err: = net.Listen ("tcp", ": 9000")     if err! = nil {         log.Fatalln (err.Error ())     }     defer server.Close ()     for {         conn, err: = server.Accept ()         if err! = nil {             log.Fatalln (err.Error ())         }         go handleConn (conn)     } }