在Golang中使用net/http存储每个请求的结构值。

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

Struct value been stored in every request Golang using net/http

问题

我是新手学习 Golang,我正在测试 net/http 包来运行一些路径,但是我遇到了一些我不理解的问题。

以下是我的代码:

  1. package main
  2. import (
  3. "fmt"
  4. "net/http"
  5. )
  6. type Content struct {
  7. Data map[interface{}]interface{}
  8. }
  9. func main() {
  10. mux := http.NewServeMux()
  11. mux.Handle("/favicon.ico", http.NotFoundHandler())
  12. mux.HandleFunc("/", Index)
  13. mux.HandleFunc("/test", Testhandler)
  14. http.ListenAndServe(":8080", mux)
  15. }
  16. func Index(w http.ResponseWriter, r *http.Request) {
  17. if r.URL.Path != "/" {
  18. fmt.Println("404")
  19. return
  20. }
  21. fmt.Println("index content ", Content)
  22. }
  23. func Testhandler(w http.ResponseWriter, r *http.Request) {
  24. data := make(map[interface{}]interface{})
  25. data["data1"] = "data 1 content"
  26. data["data2"] = "data 2 content"
  27. Content.Data = data
  28. fmt.Println("test content ", Content)
  29. }

所以,当我访问 http://localhost:8080/ 时,我得到了空的内容 index content {{false } map[]}

而当我访问 http://localhost:8080/test 时,我得到了正确的内容,test content {{false } map[data1:data 1 content data2:data 2 content]}

但是当我回到首页 http://localhost:8080/ 时,那里已经有内容了,index content {{false } map[data1:data 1 content data2:data 2 content]}

所以问题是,为什么当我回到首页时,我没有得到空的结构体内容?我以为结构体会在每个请求时都处于初始状态?HTTP 应该是无状态的,对吗?

英文:

I am new to Golang, I am testing the net/http to run some path but I got some problem that I don't understand.

Here is my codes.

  1. package main
  2. import (
  3. "fmt"
  4. "net/http"
  5. )
  6. type Content struct {
  7. Data map[interface{}]interface{}
  8. }
  9. func main() {
  10. mux := http.NewServeMux()
  11. mux.Handle("/favicon.ico", http.NotFoundHandler())
  12. mux.HandleFunc("/", Index)
  13. mux.HandleFunc("/test", Testhandler)
  14. http.ListenAndServe(":8080", mux)
  15. }
  16. func Index(w http.ResponseWriter, r *http.Request) {
  17. if r.URL.Path != "/" {
  18. fmt.Println("404");
  19. return
  20. }
  21. fmt.Println("index content ", Content)
  22. }
  23. func Testhandler(w http.ResponseWriter, r *http.Request) {
  24. data := make(map[interface{}]interface{})
  25. data["data1"] = "data 1 content"
  26. data["data2"] = "data 2 content"
  27. Content.Data = data
  28. fmt.Println("test content ", Content)
  29. }

So, if I go to index http://localhost:8080/, I got empty content index content {{false } map[]} ,

And I goto http://localhost:8080/test I got the content correctly , test content {{false } map[data1:data 1 content data2:data 2 content]},

But when I go back to index http://localhost:8080/ there already content there index content {{false } map[data1:data 1 content data2:data 2 content]},

So question here, why am I not getting the empty struct content when I back to the index? I thought the struct will be in initial state with every single request? The http should be stateless, right?

答案1

得分: 1

你可能正在经历的是这段代码或类似的代码的结果(你的代码无法编译):

  1. package main
  2. import (
  3. "fmt"
  4. "net/http"
  5. )
  6. var Content struct {
  7. Data map[interface{}]interface{}
  8. }
  9. func main() {
  10. mux := http.NewServeMux()
  11. mux.Handle("/favicon.ico", http.NotFoundHandler())
  12. mux.HandleFunc("/", Index)
  13. mux.HandleFunc("/test", Testhandler)
  14. http.ListenAndServe(":8080", mux)
  15. }
  16. func Index(w http.ResponseWriter, r *http.Request) {
  17. if r.URL.Path != "/" {
  18. fmt.Println("404")
  19. return
  20. }
  21. fmt.Println("index content ", Content)
  22. }
  23. func Testhandler(w http.ResponseWriter, r *http.Request) {
  24. data := make(map[interface{}]interface{})
  25. data["data1"] = "data 1 content"
  26. data["data2"] = "data 2 content"
  27. Content.Data = data
  28. fmt.Println("test content ", Content)
  29. }

解决方案

你创建了一个全局变量 Content,它在对 web 服务器的多次调用之间保持状态。你可能想要的是这样的:

  1. package main
  2. import (
  3. "fmt"
  4. "net/http"
  5. )
  6. type Content struct {
  7. Data map[interface{}]interface{}
  8. }
  9. func main() {
  10. mux := http.NewServeMux()
  11. mux.Handle("/favicon.ico", http.NotFoundHandler())
  12. mux.HandleFunc("/", Index)
  13. mux.HandleFunc("/test", Testhandler)
  14. http.ListenAndServe(":8080", mux)
  15. }
  16. func Index(w http.ResponseWriter, r *http.Request) {
  17. var c Content
  18. if r.URL.Path != "/" {
  19. fmt.Println("404")
  20. return
  21. }
  22. fmt.Println("index content ", c)
  23. }
  24. func Testhandler(w http.ResponseWriter, r *http.Request) {
  25. var c Content
  26. data := make(map[interface{}]interface{})
  27. data["data1"] = "data 1 content"
  28. data["data2"] = "data 2 content"
  29. c.Data = data
  30. fmt.Println("test content ", c)
  31. }

所做的更改

  • Content 声明为类型,就像你在示例中已经做的那样(这样它不再是全局变量,而是定义了一个我们可以重用的类型)
  • 在需要的每个调用中声明 Content(不要全局声明,因为我们不希望它在服务器调用之间保持内容)

要点

在使用类型之前,你必须先声明一个变量。这就是为什么你的示例无法构建的原因。如果你尝试这样做,Go 将会抱怨 Content 不是一个表达式。

英文:

What you are probably experiencing is the result of this code or something similar (your code does not compile):

  1. package main
  2. import (
  3. "fmt"
  4. "net/http"
  5. )
  6. var Content struct {
  7. Data map[interface{}]interface{}
  8. }
  9. func main() {
  10. mux := http.NewServeMux()
  11. mux.Handle("/favicon.ico", http.NotFoundHandler())
  12. mux.HandleFunc("/", Index)
  13. mux.HandleFunc("/test", Testhandler)
  14. http.ListenAndServe(":8080", mux)
  15. }
  16. func Index(w http.ResponseWriter, r *http.Request) {
  17. if r.URL.Path != "/" {
  18. fmt.Println("404")
  19. return
  20. }
  21. fmt.Println("index content ", Content)
  22. }
  23. func Testhandler(w http.ResponseWriter, r *http.Request) {
  24. data := make(map[interface{}]interface{})
  25. data["data1"] = "data 1 content"
  26. data["data2"] = "data 2 content"
  27. Content.Data = data
  28. fmt.Println("test content ", Content)
  29. }

Solution

With this you are creating a global variable Content that keeps its state across calls to the webserver. What you probably intended is this:

  1. package main
  2. import (
  3. "fmt"
  4. "net/http"
  5. )
  6. type Content struct {
  7. Data map[interface{}]interface{}
  8. }
  9. func main() {
  10. mux := http.NewServeMux()
  11. mux.Handle("/favicon.ico", http.NotFoundHandler())
  12. mux.HandleFunc("/", Index)
  13. mux.HandleFunc("/test", Testhandler)
  14. http.ListenAndServe(":8080", mux)
  15. }
  16. func Index(w http.ResponseWriter, r *http.Request) {
  17. var c Content
  18. if r.URL.Path != "/" {
  19. fmt.Println("404")
  20. return
  21. }
  22. fmt.Println("index content ", c)
  23. }
  24. func Testhandler(w http.ResponseWriter, r *http.Request) {
  25. var c Content
  26. data := make(map[interface{}]interface{})
  27. data["data1"] = "data 1 content"
  28. data["data2"] = "data 2 content"
  29. c.Data = data
  30. fmt.Println("test content ", c)
  31. }

Changes made

  • make Content a type as you already did in your sample (that way it is not a global variable any more but defining a type we can reuse)
  • declare Content in each call where it is needed (not globally as we do not want it to keep its content across server calls)

Essence

You cannot use a type without declaring a variable from it first. That is why your sample did not build. If you try go will complain that Content is not an expression.

huangapple
  • 本文由 发表于 2017年8月11日 03:18:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/45621902.html
匿名

发表评论

匿名网友

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

确定