我正在尝试学习Go Web编程,这是一个简单的Web服务器:它可以打印出被调用的时间。
package main import ( "fmt" "net/http" ) var calls int // HelloWorld print the times being called. func HelloWorld(w http.ResponseWriter, r *http.Request){ calls++ fmt.Fprintf(w, "You've called me %d times", calls) } func main() { fmt.Printf("Started server at http://localhost%v.\n", 5000) http.HandleFunc("/", HelloWorld) http.ListenAndServe(":5000", nil) }
刷新页面时,我得到:
You've called me 1 times You've called me 3 times You've called me 5 times ....
问题:为什么是1、3、5倍而不是1,2,3 …?该函数HelloWorld的调用顺序是什么?
HelloWorld
这是因为每个传入请求都被路由到您的HelloWorld()处理函数,并且浏览器在后台进行了多次调用,尤其是/favicon.ico。
HelloWorld()
/favicon.ico
并且由于您的Web服务器没有发送回有效的网站图标,因此当您在浏览器中刷新页面时,它将再次请求它。
在Chrome上尝试:打开开发人员工具(CTRL+SHIFT+I),然后选择“网络”标签。点击刷新,您将看到2个新条目:
CTRL+SHIFT+I
Name Status Type -------------------------------------------------------- localhost 200 document favicon.ico 200 text/plain
由于您的计数器以0(类型的默认值int)开头,因此您只需将其递增一次,然后发送回即可1。然后,请求favicon.ico再次将其递增(2),但不显示结果。然后,如果您刷新,它将再次增加到,3然后将其发送回,依此类推。
0
int
1
favicon.ico
2
3
另请注意,多个goroutine可以同时处理请求,因此您的解决方案会遇到麻烦。您应该同步对calls变量的访问,或者使用sync/atomic软件包安全地增加计数器,例如:
calls
sync/atomic
var calls int64 func HelloWorld(w http.ResponseWriter, r *http.Request) { count := atomic.AddInt64(&calls, 1) fmt.Fprintf(w, "You've called me %d times", count) }
一个简单的“修复”来实现您想要的,将是检查请求路径,如果它不是root "/",请不要增加,例如:
"/"
func HelloWorld(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { return } count := atomic.AddInt64(&calls, 1) fmt.Fprintf(w, "You've called me %d times", count) }
您也可以选择仅排除对的请求favicon.ico,例如:
if r.URL.Path == "/favicon.ico" { return }