Golang – 在向MySQL数据库插入数据时出现意外的流结束

huangapple go评论91阅读模式
英文:

Golang - unexpected end of stream while inserting data to MySQL DB

问题

我目前正在使用Golang编写一段代码,用于处理POST请求并将数据存储到MySQL数据库中。

以下是我目前编写的代码:

package main

import (
	"fmt"
	"os"
	"log"
	"net/http"
	"database/sql"
	"golang.org/x/crypto/bcrypt"
	_ "github.com/go-sql-driver/mysql"
)

var myLogger *log.Logger
var db *sql.DB
var err error

type UserRegistrationData struct {
	email    string
	password string
}

func handler(w http.ResponseWriter, r *http.Request) {
	myLogger = log.New(os.Stdout, "INFO: ", log.LstdFlags)

	var email string = r.PostFormValue("email")
	var password string = r.PostFormValue("password")

	data := UserRegistrationData{email, password}
	jsonEncoded, _ := json.Marshal(data)

	myLogger.Println("Success")

	hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	_, err = db.Exec("INSERT INTO users (email, password) VALUES (?, ?)", email, hashedPassword)
}

func initialiseDB() {
	db, err := sql.Open("mysql", "root:@/authenticationgolang")

	if err != nil {
		panic(err.Error())
	}

	defer db.Close()
}

func main() {
	initialiseDB()
	http.HandleFunc("/call", handler)
	http.ListenAndServe(":8080", nil)
}

当我运行这段代码并尝试保存数据时,我一直收到以下消息。

unexpected end of stream on Connection{10.10.10.153:8080, proxy=DIRECT@hostAddress=/10.10.10.153:8080 cipherSuite=none protocol=http/1.1}

日志似乎指出这一行有问题,我想请人修复这个问题。

_, err = db.Exec("INSERT INTO users (email, password) VALUES (?, ?)", email, hashedPassword)

补充 这是我在控制台上收到的日志消息。

2017/05/18 14:47:52 http: panic serving 10.10.10.58:41668: runtime error: invalid memory address or nil pointer dereference
goroutine 20 [running]:
net/http.(*conn).serve.func1(0xc4201360a0)
	/usr/local/Cellar/go/1.8.1/libexec/src/net/http/server.go:1721 +0xd0
panic(0x1288b60, 0x1424e70)
	/usr/local/Cellar/go/1.8.1/libexec/src/runtime/panic.go:489 +0x2cf
database/sql.(*DB).conn(0x0, 0x14027c0, 0xc420010450, 0xc420034801, 0x10000000142ec80, 0x1600960, 0x2)
	/usr/local/Cellar/go/1.8.1/libexec/src/database/sql/sql.go:896 +0x3a
database/sql.(*DB).exec(0x0, 0x14027c0, 0xc420010450, 0x12e699d, 0x31, 0xc420045c58, 0x2, 0x2, 0x1, 0x0, ...)
	/usr/local/Cellar/go/1.8.1/libexec/src/database/sql/sql.go:1183 +0xb9
database/sql.(*DB).ExecContext(0x0, 0x14027c0, 0xc420010450, 0x12e699d, 0x31, 0xc420045c58, 0x2, 0x2, 0x126ed20, 0xc42013c440, ...)
	/usr/local/Cellar/go/1.8.1/libexec/src/database/sql/sql.go:1165 +0xbc
database/sql.(*DB).Exec(0x0, 0x12e699d, 0x31, 0xc420034c58, 0x2, 0x2, 0x3c, 0x0, 0x0, 0x0)
	/usr/local/Cellar/go/1.8.1/libexec/src/database/sql/sql.go:1179 +0x85
main.handler(0x14022c0, 0xc42014a0e0, 0xc420144100)
	/Users/marshall/documents/projects/authenticationgolang/helloworld.go:40 +0x530
net/http.HandlerFunc.ServeHTTP(0x12ea668, 0x14022c0, 0xc42014a0e0, 0xc420144100)
	/usr/local/Cellar/go/1.8.1/libexec/src/net/http/server.go:1942 +0x44
net/http.(*ServeMux).ServeHTTP(0x142e060, 0x14022c0, 0xc42014a0e0, 0xc420144100)
	/usr/local/Cellar/go/1.8.1/libexec/src/net/http/server.go:2238 +0x130
net/http.serverHandler.ServeHTTP(0xc42009a2c0, 0x14022c0, 0xc42014a0e0, 0xc420144100)
	/usr/local/Cellar/go/1.8.1/libexec/src/net/http/server.go:2568 +0x92
net/http.(*conn).serve(0xc4201360a0, 0x1402780, 0xc42011e580)
	/usr/local/Cellar/go/1.8.1/libexec/src/net/http/server.go:1825 +0x612
created by net/http.(*Server).Serve
	/usr/local/Cellar/go/1.8.1/libexec/src/net/http/server.go:2668 +0x2ce
英文:

I'm currently writing a code in Golang that handles POST requests and store data into the MySQL database.

Here's what I've written so far.

package main

import (
	"fmt"
	"os"
	"log"
	"net/http"
	"database/sql"
	"golang.org/x/crypto/bcrypt"
	_ "github.com/go-sql-driver/mysql"
)

var myLogger *log.Logger
var db *sql.DB
var err error

type UserRegistrationData struct {
	email string
	password string
}

func handler(w http.ResponseWriter, r *http.Request) {
	myLogger = log.New(os.Stdout, "INFO: ", log.LstdFlags)

	var email string = r.PostFormValue("email")
	var password string = r.PostFormValue("password")

	data := UserRegistrationData{email, password}
	jsonEncoded, _ := json.Marshal(data)

	myLogger.Println("Success")

	hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	_, err = db.Exec("INSERT INTO users (email, password) VALUES (?, ?)", email, hashedPassword)
}

func initialiseDB() {
	db, err := sql.Open("mysql", "root:@/authenticationgolang")

	if err != nil {
		panic(err.Error())
	}

	defer db.Close()
}

func main() {
	initialiseDB()
	http.HandleFunc("/call", handler)
	http.ListenAndServe(":8080", nil)
}

As I run the code and try to save the data, I keep getting the following message.

unexpected end of stream on Connection{10.10.10.153:8080, proxy=DIRECT@hostAddress=/10.10.10.153:8080 cipherSuite=none protocol=http/1.1}

The log seems to point out that this line has a problem, and I would like to ask somebody for fixing this out.

_, err = db.Exec("INSERT INTO users (email, password) VALUES (?, ?)", email, hashedPassword)

Added Here's the log message I get on the console.

2017/05/18 14:47:52 http: panic serving 10.10.10.58:41668: runtime error: invalid memory address or nil pointer dereference
goroutine 20 [running]:
net/http.(*conn).serve.func1(0xc4201360a0)
	/usr/local/Cellar/go/1.8.1/libexec/src/net/http/server.go:1721 +0xd0
panic(0x1288b60, 0x1424e70)
	/usr/local/Cellar/go/1.8.1/libexec/src/runtime/panic.go:489 +0x2cf
database/sql.(*DB).conn(0x0, 0x14027c0, 0xc420010450, 0xc420034801, 0x10000000142ec80, 0x1600960, 0x2)
	/usr/local/Cellar/go/1.8.1/libexec/src/database/sql/sql.go:896 +0x3a
database/sql.(*DB).exec(0x0, 0x14027c0, 0xc420010450, 0x12e699d, 0x31, 0xc420045c58, 0x2, 0x2, 0x1, 0x0, ...)
	/usr/local/Cellar/go/1.8.1/libexec/src/database/sql/sql.go:1183 +0xb9
database/sql.(*DB).ExecContext(0x0, 0x14027c0, 0xc420010450, 0x12e699d, 0x31, 0xc420045c58, 0x2, 0x2, 0x126ed20, 0xc42013c440, ...)
	/usr/local/Cellar/go/1.8.1/libexec/src/database/sql/sql.go:1165 +0xbc
database/sql.(*DB).Exec(0x0, 0x12e699d, 0x31, 0xc420034c58, 0x2, 0x2, 0x3c, 0x0, 0x0, 0x0)
	/usr/local/Cellar/go/1.8.1/libexec/src/database/sql/sql.go:1179 +0x85
main.handler(0x14022c0, 0xc42014a0e0, 0xc420144100)
	/Users/marshall/documents/projects/authenticationgolang/helloworld.go:40 +0x530
net/http.HandlerFunc.ServeHTTP(0x12ea668, 0x14022c0, 0xc42014a0e0, 0xc420144100)
	/usr/local/Cellar/go/1.8.1/libexec/src/net/http/server.go:1942 +0x44
net/http.(*ServeMux).ServeHTTP(0x142e060, 0x14022c0, 0xc42014a0e0, 0xc420144100)
	/usr/local/Cellar/go/1.8.1/libexec/src/net/http/server.go:2238 +0x130
net/http.serverHandler.ServeHTTP(0xc42009a2c0, 0x14022c0, 0xc42014a0e0, 0xc420144100)
	/usr/local/Cellar/go/1.8.1/libexec/src/net/http/server.go:2568 +0x92
net/http.(*conn).serve(0xc4201360a0, 0x1402780, 0xc42011e580)
	/usr/local/Cellar/go/1.8.1/libexec/src/net/http/server.go:1825 +0x612
created by net/http.(*Server).Serve
	/usr/local/Cellar/go/1.8.1/libexec/src/net/http/server.go:2668 +0x2ce

答案1

得分: 2

根据你收到的错误信息:

> runtime error: invalid memory address or nil pointer dereference
> goroutine 20 [running]:

你的 handler() 函数中的 db 变量是空指针,这是问题的根源。

要修复这个问题,你可以在 initialiseDB() 函数中移除 :。因为在这里你是将值赋给函数内部的新变量,而不是全局变量。像这样:

func initialiseDB() {
    var err error
    db, err = sql.Open("mysql", "root:@/authenticationgolang")

    if err != nil {
        panic(err.Error())
    }
}

建议

然后在你的代码中,请检查函数返回的错误值,像这样:

data := UserRegistrationData{email, password}
jsonEncoded, err := json.Marshal(data)
if err != nil {
    myLogger.Fatal(err)
}

myLogger.Println("Success")

hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
    myLogger.Fatal(err)
}
_, err = db.Exec("INSERT INTO users (email, password) VALUES (?, ?)", email, hashedPassword)
if err != nil {
    myLogger.Fatal(err)
}

或者,如果你不想停止应用程序的运行,你可以使用 Println(),像这样:

if err != nil {
    myLogger.Println(err)
    return
}

return 语句将停止代码的执行。使用这种方法,你将会注意到服务器端发生的错误,并且知道错误发生在哪一行。

并且不要忘记在请求成功时发送响应,像这样:

resp := struct {
    Message string
}{
    Message: "your message",
}

// 写入响应
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(resp)

希望对你有所帮助。

英文:

From error message that you got :

> runtime error: invalid memory address or nil pointer dereference
> goroutine 20 [running]:

Your db varible in your hanlder() is nil that's the root of the cause.

to fix this you can remove your : in your initialiseDB(). Because here you are assign to new variable local in the function not to your global variable. Like this :

func initialiseDB() {
    var err error
    db, err = sql.Open("mysql", "root:@/authenticationgolang")

    if err != nil {
        panic(err.Error())
    }
}

Suggestion

And then on your code please check the error value returned by the function like :

data := UserRegistrationData{email, password}
    jsonEncoded, err := json.Marshal(data)
    if err !=nil {
        myLogger.Fatal(err)
    }

    myLogger.Println("Success")

    hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
    if err != nil {
       myLogger.Fatal(err)
    }
    _, err = db.Exec("INSERT INTO users (email, password) VALUES (?, ?)", email, hashedPassword)
   if err != nil {
       myLogger.Fatal(err)
   }

Or you can use Println() in case you don't want to stop your application to run like this :

if err != nil {
   myLogger.Println(err)
   return
}

The return will stop the execution of the code. Using this approach you will notice if somethings error happens on your server side and you know which line the error happened.

And don't forget to send your response if the request success like :

resp := struct {
	Message string
}{
    Message : "your message",
}

// Write the response
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(resp)

Hope it helps.

huangapple
  • 本文由 发表于 2017年5月18日 13:05:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/44038971.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定