为什么这个简单的 Web 服务器被称为偶数次? [英] Why this simple web server is called even number times?
问题描述
我正在尝试学习 Go 网络编程,这里有一个简单的网络服务器:它打印出被调用的时间.
I'm trying to learn Go web programming, and here is a simple web server: it prints out the times being called.
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.
", 5000)
http.HandleFunc("/", HelloWorld)
http.ListenAndServe(":5000", nil)
}
当我刷新页面时,我得到:
When I refresh the page, I got:
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
函数的调用顺序是什么?
Question: Why it is 1, 3, 5 times, rather than 1,2,3...? What's the order of the function HelloWorld
being called?
推荐答案
这是因为每个传入的请求都会路由到您的 HelloWorld()
处理程序函数,并且浏览器会在后台进行多次调用,专门针对 /favicon.ico
.
It is because every incoming request is routed to your HelloWorld()
handler function, and the browser makes multiple calls under the hood, specifically to /favicon.ico
.
由于您的网络服务器没有发回有效的图标,当您在浏览器中刷新页面时,它会再次请求它.
And since your web server does not send back a valid favicon, it will request it again when you refresh the page in the browser.
使用 Chrome 试试:打开开发者工具 (CTRL+SHIFT+I),然后选择网络"选项卡.点击刷新,您将看到 2 个新条目:
Try it with Chrome: open the Developer tools (CTRL+SHIFT+I), and choose the "Network" tab. Hit refresh, and you will see 2 new entries:
Name Status Type
--------------------------------------------------------
localhost 200 document
favicon.ico 200 text/plain
由于您的计数器以 0
开头(int
类型的默认值),您将其递增一次并返回 1
.然后对 favicon.ico
的请求再次增加它(2
),但结果没有显示.然后,如果您刷新,它会再次增加到 3
,然后您将其发回,等等.
Since your counter starts with 0
(default value for type int
), you increment it once and you send back 1
. Then the request for favicon.ico
increments it again (2
), but the result is not displayed. Then if you refresh, it gets incremented again to 3
and you send that back, etc.
另请注意,多个 goroutine 可以同时处理请求,因此您的解决方案存在竞争.您应该同步对 calls
变量的访问,或使用 sync/atomic
包以安全地递增计数器,例如:
Also note that multiple goroutines can serve requests concurrently, so your solution has a race. You should synchronize access to the calls
variable, or use the sync/atomic
package to increment the counter safely, for example:
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)
}
实现您想要的简单修复"是检查请求路径,如果它不是根"/"
,则不要增加,例如:
A simple "fix" to achieve what you want would be to check the request path, and if it is not the root "/"
, don't increment, e.g.:
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
的请求,例如:
You may also choose to only exclude requests for favicon.ico
, e.g.:
if r.URL.Path == "/favicon.ico" {
return
}
这篇关于为什么这个简单的 Web 服务器被称为偶数次?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!