问题
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.\n", 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
....
Question: Why it is 1, 3, 5 times, rather than 1,2,3...? What's the order of the function HelloWorld
being called?
回答1:
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.
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
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.
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)
}
You may also choose to only exclude requests for favicon.ico
, e.g.:
if r.URL.Path == "/favicon.ico" {
return
}
来源:https://stackoverflow.com/questions/35550189/why-this-simple-web-server-is-called-even-number-times