我正在尝试在Go中执行REST API。查询在放置在主处理程序中时显示(在终端中显示),但在移动到所需处理程序时在浏览器中出错。
localhost:8080 /< ------浏览器发出错误(未显示任何内容),终端显示多条错误消息 - 其中一条是:
http:panic serving [:: 1]:51100:运行时错误:无效的内存地址或nil指针取消引用
localhost:8080 / getuser< ---给出正确答案
的getUser
package main
import (
"fmt"
"log"
"net/http"
"database/sql"
_ "github.com/lib/pq"
)
const (
host = "127.0.0.1"
port = 5432
user = "test"
password = "pw"
dbname = "Test"
)
var db *sql.DB
type User struct {
USER_ID string
USER_NAME string
}
func handleRequests() {
http.HandleFunc("/", index)
http.HandleFunc("/getuser", Getuser)
}
func index(w http.ResponseWriter, r *http.Request){
rows, err := db.Query(`SELECT "USER_ID","USER_NAME" FROM users`)
if err != nil {
http.Error(w, http.StatusText(500), 500)
return
}
defer rows.Close()
for rows.Next() {
user := User{}
err := rows.Scan(&user.USER_ID, &user.USER_NAME)
if err != nil {
http.Error(w, http.StatusText(500), 500)
}
fmt.Fprintf(w, "%s, %s\n", user.USER_ID, user.USER_NAME)
}
}
func Getuser(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Getuser") // <-------------------------this works!
}
func main() {
handleRequests()
psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
"password=%s dbname=%s sslmode=require",
host, port, user, password, dbname)
db, err := sql.Open("postgres", psqlInfo)
if err != nil {
log.Fatalln(err)
}
if err != nil {
panic(err)
}
defer db.Close()
err = db.Ping()
if err != nil {
panic(err)
}
log.Fatal(http.ListenAndServe(":8080", nil))
}
修改
终端
中的完整错误列表由net / http。(* Server).Serve创建 /usr/local/go/src/net/http/server.go:2795 + 0x27b 2018/03/23 08:36:39 http:panic serving [:: 1]:51390:运行时错误:无效 内存地址或无指针取消引用goroutine 36 [运行]: 净/ HTTP(*康恩).serve.func1(0xc4201d80a0) /usr/local/go/src/net/http/server.go:1726 + 0xd0恐慌(0x1294460,0x1471840) /usr/local/go/src/runtime/panic.go:505 + 0x229 database / sql。(* DB).conn(0x0,0x13277e0,0xc42009e020,0xc420028f01, 0xc4200a0218,0xc4200a0220,0xc4201e8b01) /usr/local/go/src/database/sql/sql.go:1015 + 0x3a database / sql。(* DB).query(0x0,0x13277e0,0xc42009e020,0x12f7553, 0x26,0x0,0x0,0x0,0x12ec601,0x8,...) /usr/local/go/src/database/sql/sql.go:1437 + 0x66
database / sql。(* DB).QueryContext(0x0,0x13277e0,0xc42009e020, 0x12f7553,0x26,0x0,0x0,0x0,0x10825ed,0xc4201d0180,...) /usr/local/go/src/database/sql/sql.go:1419 + 0xd2 database / sql。(* DB).Query(0x0,0x12f7553,0x26,0x0,0x0,0x0, 0xc4201ec070,0x8000000000000000,0x0) /usr/local/go/src/database/sql/sql.go:1433 + 0x82 main.Getsign(0x13275a0,0xc4202020e0,0xc4201f4100) /Users/sibert/go/src/main/api.go:55 + 0x65 net / http.HandlerFunc.ServeHTTP(0x1302020,0x13275a0,0xc4202020e0, 0xc4201f4100) /usr/local/go/src/net/http/server.go:1947 + 0x44 net / http。(* ServeMux).ServeHTTP(0x147cc00,0x13275a0,0xc4202020e0, 0xc4201f4100) /usr/local/go/src/net/http/server.go:2337 + 0x130 net / http.serverHandler.ServeHTTP(0xc42009b2b0,0x13275a0, 0xc4202020e0,0xc4201f4100) /usr/local/go/src/net/http/server.go:2694 + 0xbc net / http。(* conn).serve(0xc4201d80a0,0x13277a0,0xc4201b4280) /usr/local/go/src/net/http/server.go:1830 + 0x651由net / http。(* Server)创建.Serve /usr/local/go/src/net/http/server.go:2795 + 0x27b 2018/03/23 08:36:39 http:panic serving [:: 1]:51391:运行时错误:无效 内存地址或零指针取消引用goroutine 24 [运行]: 净/ HTTP(*康恩).serve.func1(0xc4200b4b40) /usr/local/go/src/net/http/server.go:1726 + 0xd0恐慌(0x1294460,0x1471840) /usr/local/go/src/runtime/panic.go:505 + 0x229 database / sql。(* DB).conn(0x0,0x13277e0,0xc42009e020,0xc420024501, 0xc4200a0318,0xc4200a0320,0xc420052b01) /usr/local/go/src/database/sql/sql.go:1015 + 0x3a database / sql。(* DB).query(0x0,0x13277e0,0xc42009e020,0x12f7553, 0x26,0x0,0x0,0x0,0x12ec601,0x8,...) /usr/local/go/src/database/sql/sql.go:1437 + 0x66 database / sql。(* DB).QueryContext(0x0,0x13277e0,0xc42009e020, 0x12f7553,0x26,0x0,0x0,0x0,0x10825ed,0xc420140480,...) /usr/local/go/src/database/sql/sql.go:1419 + 0xd2 database / sql。(* DB).Query(0x0,0x12f7553,0x26,0x0,0x0,0x0, 0xc42009eb10,0x8000000000000000,0x0) /usr/local/go/src/database/sql/sql.go:1433 + 0x82 main.Getsign(0x13275a0,0xc42019e0e0,0xc42019a300) /Users/sibert/go/src/main/api.go:55 + 0x65 net / http.HandlerFunc.ServeHTTP(0x1302020,0x13275a0,0xc42019e0e0, 0xc42019a300) /usr/local/go/src/net/http/server.go:1947 + 0x44 net / http。(* ServeMux).ServeHTTP(0x147cc00,0x13275a0,0xc42019e0e0, 0xc42019a300) /usr/local/go/src/net/http/server.go:2337 + 0x130 net / http.serverHandler.ServeHTTP(0xc42009b2b0,0x13275a0, 0xc42019e0e0,0xc42019a300) /usr/local/go/src/net/http/server.go:2694 + 0xbc net / http。(* conn).serve(0xc4200b4b40,0x13277a0,0xc4200a0780) /usr/local/go/src/net/http/server.go:1830 + 0x651由net / http。(* Server)创建.Serve /usr/local/go/src/net/http/server.go:2795 + 0x27b
答案 0 :(得分:1)
您遇到的是变量阴影的经典案例。
:=
会创建一个新的db
变量,该变量会影响您的包级别db
变量。 db
的设置值仅存在于main函数的范围内,而包级别db
变量仍作为nil指针,因此当您尝试在nil
上执行方法调用时,在你的索引处理程序中,你会感到恐慌。
Getuser处理程序工作的原因与DefaultServeMux无关,原因很简单,因为您没有尝试访问nil值的成员函数。
解决此问题的方法是在预先处理err
变量并将:=
更改为简单作业=
func main() {
// ...
var err error
// this will now correctly set your package level variable
db, err = sql.Open("postgres", psqlInfo)
if err != nil {
log.Fatalln(err)
}
// ...
}