Golang中访问计数Cookie为何会同时计数两次

Golang中访问计数Cookie为何会同时计数两次 我正在学习Web开发和Cookie。 在我的代码中,当访问 localhost:8084/abc 时,用于统计访问次数的Cookie工作正常。 它会逐一累加访问次数。 但是,当我访问默认路径("/")时,Cookie会同时将访问次数计数两次。 有人知道这个问题以及如何解决吗?

package main

import (
	"fmt"
	"net/http"
	"strconv"
	"text/template"
)

func main() {
	http.HandleFunc("/", ab)
	http.HandleFunc("/abc", abc)
	http.ListenAndServe(":8084", nil)

}
func abc(w http.ResponseWriter, r *http.Request) {
	c, err := r.Cookie("VisitNum")
	if err != nil {
		fmt.Fprint(w, err, "   1")
	}
	tpl, err := template.ParseFiles("index2.html")
	if err != nil {
		fmt.Fprint(w, err, "   2")
	}
	tpl.Execute(w, c.Value)

}
func ab(w http.ResponseWriter, r *http.Request) {
	c, _ := r.Cookie("VisitNum")
	if c == nil {
		c := &http.Cookie{
			Name:  "VisitNum",
			Value: "1",
		}
		http.SetCookie(w, c)
	} else {
		cin, err := strconv.Atoi(c.Value)
		if err != nil {
			fmt.Fprint(w, err, "   4")
		}
		cin++
		c.Value = strconv.Itoa(cin)
		http.SetCookie(w, c)
	}
	tpl, _ := template.ParseFiles("index.html")
	tpl.Execute(w, "aaa")
}

更多关于Golang中访问计数Cookie为何会同时计数两次的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

检查请求的 Method。你可能收到了除 GET 之外的其他请求。

更多关于Golang中访问计数Cookie为何会同时计数两次的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


处理路径“/”会被视为一个目录,并将处理所有未被其他处理程序匹配的请求。就像处理“/api/”也会处理对“/api/foobar”的请求一样。

如果你打开浏览器的开发者工具和网络标签页,你将看到所有发往你服务器的请求。大多数浏览器会搜索网站图标(即浏览器标签页上每个页面不同的小图标),并在后台静默调用“/favicon.ico”。这个调用会被你的“/”处理程序接收。

你可以通过在处理程序中添加 fmt.Printf("%+v\n", r) 来调试这个问题,占位符“%+v”会打印请求对象的所有详细信息,你可以看到被调用的路径是什么。

fmt.Printf("%+v\n", r)

这个问题是由于浏览器对默认路径"/"的请求行为导致的。当访问根路径时,浏览器通常会同时请求/favicon.ico,导致处理函数被调用两次。

以下是修改后的代码,通过检查请求路径来避免重复计数:

package main

import (
	"fmt"
	"net/http"
	"strconv"
	"text/template"
)

func main() {
	http.HandleFunc("/", ab)
	http.HandleFunc("/abc", abc)
	http.ListenAndServe(":8084", nil)
}

func abc(w http.ResponseWriter, r *http.Request) {
	c, err := r.Cookie("VisitNum")
	if err != nil {
		fmt.Fprint(w, err, "   1")
	}
	tpl, err := template.ParseFiles("index2.html")
	if err != nil {
		fmt.Fprint(w, err, "   2")
	}
	tpl.Execute(w, c.Value)
}

func ab(w http.ResponseWriter, r *http.Request) {
	// 忽略对favicon.ico的请求
	if r.URL.Path == "/favicon.ico" {
		return
	}
	
	c, _ := r.Cookie("VisitNum")
	if c == nil {
		c := &http.Cookie{
			Name:  "VisitNum",
			Value: "1",
		}
		http.SetCookie(w, c)
	} else {
		cin, err := strconv.Atoi(c.Value)
		if err != nil {
			fmt.Fprint(w, err, "   4")
		}
		cin++
		c.Value = strconv.Itoa(cin)
		http.SetCookie(w, c)
	}
	tpl, _ := template.ParseFiles("index.html")
	tpl.Execute(w, "aaa")
}

另一种更通用的解决方案是使用中间件来统计访问次数,避免路径相关的重复计数:

package main

import (
	"fmt"
	"net/http"
	"strconv"
	"text/template"
)

func main() {
	http.HandleFunc("/", ab)
	http.HandleFunc("/abc", abc)
	http.ListenAndServe(":8084", nil)
}

func abc(w http.ResponseWriter, r *http.Request) {
	c, err := r.Cookie("VisitNum")
	if err != nil {
		fmt.Fprint(w, err, "   1")
	}
	tpl, err := template.ParseFiles("index2.html")
	if err != nil {
		fmt.Fprint(w, err, "   2")
	}
	tpl.Execute(w, c.Value)
}

func ab(w http.ResponseWriter, r *http.Request) {
	// 只在处理主页面请求时计数
	if r.URL.Path == "/" {
		c, _ := r.Cookie("VisitNum")
		if c == nil {
			c := &http.Cookie{
				Name:  "VisitNum",
				Value: "1",
			}
			http.SetCookie(w, c)
		} else {
			cin, err := strconv.Atoi(c.Value)
			if err != nil {
				fmt.Fprint(w, err, "   4")
			}
			cin++
			c.Value = strconv.Itoa(cin)
			http.SetCookie(w, c)
		}
	}
	
	tpl, _ := template.ParseFiles("index.html")
	tpl.Execute(w, "aaa")
}

还可以使用请求方法过滤来避免OPTIONS预检请求导致的重复计数:

func ab(w http.ResponseWriter, r *http.Request) {
	// 只统计GET请求
	if r.Method != http.MethodGet {
		return
	}
	
	// 忽略对favicon.ico的请求
	if r.URL.Path == "/favicon.ico" {
		return
	}
	
	c, _ := r.Cookie("VisitNum")
	if c == nil {
		c := &http.Cookie{
			Name:  "VisitNum",
			Value: "1",
		}
		http.SetCookie(w, c)
	} else {
		cin, err := strconv.Atoi(c.Value)
		if err != nil {
			fmt.Fprint(w, err, "   4")
		}
		cin++
		c.Value = strconv.Itoa(cin)
		http.SetCookie(w, c)
	}
	tpl, _ := template.ParseFiles("index.html")
	tpl.Execute(w, "aaa")
}
回到顶部