我正在尝试学习 Go 网络编程,这是一个简单的网络服务器:它打印出被调用的时间。
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()
处理函数,并且浏览器会在后台进行多次调用,特别是对 /favicon.ico
。
而且由于您的网络服务器没有发回有效的网站图标,当您在浏览器中刷新页面时,它会再次请求它。
用 Chrome 试试:打开开发者工具 (CTRL+SHIFT+I),然后选择“网络”选项卡。点击刷新,您将看到 2 个新条目:
Name Status Type
--------------------------------------------------------
localhost 200 document
favicon.ico 200 text/plain
由于您的计数器以 0
(类型 int
的默认值)开头,因此您将其递增一次并返回 1
。然后对 favicon.ico
的请求再次将其递增 (2
),但不显示结果。然后,如果您刷新,它会再次递增到 3
并将其发送回来,等等。
另外请注意,多个 goroutine 可以同时处理请求,因此您的解决方案存在竞争。您应该同步对 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)
}
实现您想要的简单“修复”是检查请求路径,如果它不是根 "/"
,请不要增加,例如:
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
}
关于http - 为什么这个简单的 Web 服务器会被调用偶数次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35550189/