Golang的HTTP处理程序上下文

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

golang http handler context

问题

我正在尝试理解使用以下代码中的变量作用域的Golang。在这个例子中,调用http页面将回显URI查询与Boltdb中存储的值组合起来。

问题是数据库驱动程序似乎在http处理程序上下文中无法正确运行:它既不打印到标准输出,也不打印到http请求。

我期望它打印:

>He's loving <'uri query content'> but prefers pizza (data from bolt.db driver)

如何修复这段代码?

package main

import (
    "fmt"
    "net/http"
    "log"
    "github.com/boltdb/bolt"
)

var db bolt.DB

func handler(w http.ResponseWriter, r *http.Request) {
    dberr := db.Update(func(tx *bolt.Tx) error {
        log.Println("here")
        b := tx.Bucket([]byte("MyBucket"))
        loving := b.Get([]byte("loving"))
        log.Printf("He's loving %s but prefers %s", r.URL.Path[1:], string(loving))
        fmt.Fprintf(w, "He's loving %s but prefers %s", r.URL.Path[1:], string(loving))
        return nil
    })
    if dberr != nil {
        fmt.Errorf("db update: %s", dberr)
    }
    log.Printf("Finished handling")
}

func main() {

    db, err := bolt.Open("my.db", 0600, nil)
    if err != nil {
        log.Fatal(err)
    } else {
        log.Println("database opened")
    }
    dberr := db.Update(func(tx *bolt.Tx) error {
        b, err := tx.CreateBucketIfNotExists([]byte("MyBucket"))
        if err != nil {
            return fmt.Errorf("create bucket: %s", err)
        }
        err2 := b.Put([]byte("loving"), []byte("pizza"))
        if err2 != nil {
            return fmt.Errorf("put loving: %s", err2)
        }
        loving := b.Get([]byte("loving"))
        log.Printf("He's loving %s", string(loving))
        return nil
    })

    if dberr != nil {
        fmt.Errorf("db update: %s", err)
    }
    defer db.Close()

    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)

}
英文:

I'm trying to understand variable scopes in golang with the following code.
In this example, calling in http a page will echo the uri query combined with a stored value in Boltdb.

The problem is that the database driver doesn't seem to run correctly in the http handler context: it doesn't print anything to stdout nor to the http request.

I was expecting it to print :

>He's loving <'uri query content'> but prefers pizza (data from bolt.db driver)

How to fix this code?
package main

import (
&quot;fmt&quot;
&quot;net/http&quot;
&quot;log&quot;
&quot;github.com/boltdb/bolt&quot;
)
var db bolt.DB
func handler(w http.ResponseWriter, r *http.Request) {
dberr := db.Update(func(tx *bolt.Tx) error {
log.Println(&quot;here&quot;)
b := tx.Bucket([]byte(&quot;MyBucket&quot;))
loving := b.Get([]byte(&quot;loving&quot;))
log.Printf(&quot;He&#39;s loving %s but prefers %s&quot;,r.URL.Path[1:], string(loving))
fmt.Fprintf(w,&quot;He&#39;s loving %s but prefers %s&quot;,r.URL.Path[1:], string(loving) )
return nil
})
if dberr != nil {
fmt.Errorf(&quot;db update: %s&quot;, dberr)
}
log.Printf(&quot;Finished handling&quot;)
}
func main() {
db, err := bolt.Open(&quot;my.db&quot;, 0600, nil)
if err != nil {
log.Fatal(err)
}else{
log.Println(&quot;database opened&quot;)
}
dberr := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucketIfNotExists([]byte(&quot;MyBucket&quot;))
if err != nil {
return fmt.Errorf(&quot;create bucket: %s&quot;, err)
}
err2 := b.Put([]byte(&quot;loving&quot;), []byte(&quot;pizza&quot;))
if err2 != nil {
return fmt.Errorf(&quot;put loving: %s&quot;, err2)
}
loving := b.Get([]byte(&quot;loving&quot;))
log.Printf(&quot;He&#39;s loving %s&quot;, string(loving))
return nil
})
if dberr != nil {
fmt.Errorf(&quot;db update: %s&quot;, err)
}
defer db.Close()
http.HandleFunc(&quot;/&quot;, handler)
http.ListenAndServe(&quot;:8080&quot;, nil)
}

答案1

得分: 2

我觉得我看到了你的错误。这个问题通常比较难追踪,因为它只是等号前面的冒号。这基本上是一个作用域问题,因为你在声明 db 为全局变量的同时,又创建了一个只在主函数作用域内的 db 变量。

你使用了 db, err := ... 来赋值,而不是只用 =:= 同时会声明和推断类型。由于它也在声明变量,你在 main 函数中使用的 db 不是你在全局作用域中声明的 db。与此同时,处理程序仍然尝试使用在全局作用域中声明的 db。下面的代码与你最初的代码相同,只是在代码中添加了一些注释,以说明工作中的更改。希望这可以帮到你!

package main

import (
	"fmt"
	"log"
	"net/http"

	"github.com/boltdb/bolt"
)

var db *bolt.DB // 这将是一个指针,直到它被主函数设置为nil

func handler(w http.ResponseWriter, r *http.Request) {
	dberr := db.Update(func(tx *bolt.Tx) error {
		log.Println("here")
		b := tx.Bucket([]byte("MyBucket"))
		loving := b.Get([]byte("loving"))
		log.Printf("He's loving %s but prefers %s", r.URL.Path[1:], string(loving))
		fmt.Fprintf(w, "He's loving %s but prefers %s", r.URL.Path[1:], string(loving))
		return nil
	})
	if dberr != nil {
		fmt.Errorf("db update: %s", dberr)
	}
	log.Printf("Finished handling")
}

func main() {
	var err error                           // 这必须声明,因为下一行要将db的第一个返回值赋值给它
	db, err = bolt.Open("my.db", 0600, nil) // 注意这里的变化,不再是 `db, err := ...`,而是 `db, err = ...`
	if err != nil {
		log.Fatal(err)
	} else {
		log.Println("database opened")
	}
	dberr := db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucketIfNotExists([]byte("MyBucket"))
		if err != nil {
			return fmt.Errorf("create bucket: %s", err)
		}
		err2 := b.Put([]byte("loving"), []byte("pizza"))
		if err2 != nil {
			return fmt.Errorf("put loving: %s", err2)
		}
		loving := b.Get([]byte("loving"))
		log.Printf("He's loving %s", string(loving))
		return nil
	})

	if dberr != nil {
		fmt.Errorf("db update: %s", err)
	}
	defer db.Close()

	http.HandleFunc("/", handler)
	http.ListenAndServe(":3000", nil)
}
英文:

I think I see your bug. This one is usually a little difficult to track because its just the : in front of the equals. It was basically a scoping issue because you declared db as a global while at the same time creating a db variable that was scoped to your main function.

You used db, err := ... to assign the values instead of just =. := will both declare and infer the type. Since its also doing declaration, the db you're using in the main function is not the db you have declared in the global scope. Meanwhile the handler is still attempting to use the db that was declared in the global scope. The below code is the same code as you initially had with a few comments in the code to outline what the working changes are. Hope this helps!

package main
import (
&quot;fmt&quot;
&quot;log&quot;
&quot;net/http&quot;
&quot;github.com/boltdb/bolt&quot;
)
var db *bolt.DB // this is going to be a pointer and is going to be nil until its set by the main function
func handler(w http.ResponseWriter, r *http.Request) {
dberr := db.Update(func(tx *bolt.Tx) error {
log.Println(&quot;here&quot;)
b := tx.Bucket([]byte(&quot;MyBucket&quot;))
loving := b.Get([]byte(&quot;loving&quot;))
log.Printf(&quot;He&#39;s loving %s but prefers %s&quot;, r.URL.Path[1:], string(loving))
fmt.Fprintf(w, &quot;He&#39;s loving %s but prefers %s&quot;, r.URL.Path[1:], string(loving))
return nil
})
if dberr != nil {
fmt.Errorf(&quot;db update: %s&quot;, dberr)
}
log.Printf(&quot;Finished handling&quot;)
}
func main() {
var err error                           // this will have to be declared because of the next line to assign db the first value returned from `bolt.Open`
db, err = bolt.Open(&quot;my.db&quot;, 0600, nil) // notice that this has changed and is no longer `db, err := ...` rather its `db, err = ...`
if err != nil {
log.Fatal(err)
} else {
log.Println(&quot;database opened&quot;)
}
dberr := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucketIfNotExists([]byte(&quot;MyBucket&quot;))
if err != nil {
return fmt.Errorf(&quot;create bucket: %s&quot;, err)
}
err2 := b.Put([]byte(&quot;loving&quot;), []byte(&quot;pizza&quot;))
if err2 != nil {
return fmt.Errorf(&quot;put loving: %s&quot;, err2)
}
loving := b.Get([]byte(&quot;loving&quot;))
log.Printf(&quot;He&#39;s loving %s&quot;, string(loving))
return nil
})
if dberr != nil {
fmt.Errorf(&quot;db update: %s&quot;, err)
}
defer db.Close()
http.HandleFunc(&quot;/&quot;, handler)
http.ListenAndServe(&quot;:3000&quot;, nil)
}

huangapple
  • 本文由 发表于 2015年10月18日 22:42:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/33199261.html
匿名

发表评论

匿名网友

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

确定