为什么这个简单的Web服务器被称为偶数次?

时间:2016-02-22 09:39:01

标签: http go server

我正在尝试学习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的顺序是什么?

1 个答案:

答案 0 :(得分:12)

这是因为每个传入的请求都会路由到您的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
}