Golang中如何实现服务器响应的双重返回

Golang中如何实现服务器响应的双重返回 尝试构建一个支持多语言的简单Web应用程序,但我注意到输出语句中的内容被打印了两次:

func index(w http.ResponseWriter, r *http.Request) {
		fmt.Println(lang.Value)
		fmt.Println(cfg.Database.Username)
}

我得到的输出是:

D:\Development\GO\i18n>go run hasan/web
Listening to port: 8090
en
admin
en
admin

我的完整代码如下:

// main.go
package main

import (
	"fmt"
	"net/http"
	"os"
	"text/template"

	"gopkg.in/yaml.v2"
)

// Config ...
type Config struct {
	Server struct {
		Port string `yaml:"port"`
		Host string `yaml:"host"`
	} `yaml:"server"`
	Database struct {
		Username string `yaml:"user"`
		Password string `yaml:"pass"`
	} `yaml:"database"`
}

func processError(err error) {
	fmt.Println(err)
	os.Exit(2)
}

func readFile(cfg *Config, lang string) {
	f, err := os.Open(fmt.Sprint("configuration/", lang, ".yml"))
	if err != nil {
		processError(err)
	}
	defer f.Close()

	decoder := yaml.NewDecoder(f)
	err = decoder.Decode(cfg)
	if err != nil {
		processError(err)
	}
}

func index(w http.ResponseWriter, r *http.Request) {
	var tmpl *template.Template
	var cfg Config
	lang, err := r.Cookie("language")
	if err != nil {
		readFile(&cfg, "en")
		tmpl, _ = template.New("").ParseFiles(fmt.Sprint("templates/en/page-en.html"), "base.html")
	} else {
		readFile(&cfg, lang.Value)
		fmt.Println(lang.Value)
		fmt.Println(cfg.Database.Username)
		tmpl, _ = template.New("").ParseFiles(fmt.Sprint("templates/", lang.Value, "/page-", lang.Value, ".html"), "base.html")
	}

	tmpl.ExecuteTemplate(w, "base", nil)
}

func main() {
	port := "8090"
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./public"))))
	http.HandleFunc("/", index)
	fmt.Println("Listening to port:", port)
	error := http.ListenAndServe(":"+port, nil)
	fmt.Println(error)
}

模板文件如下:

// base.html
{{define "base"}}
<!DOCTYPE html>
<html lang="en">
    <link rel="shortcut icon" href="favicon.ico" />
    <script>
    function setLanguage(lang) {
        document.cookie = "language="+lang;
        location.reload();
    }
    </script>
<body>

    <a href="#" onclick="setLanguage('en')">English</a> 
    <a href="#" onclick="setLanguage('ar')">عربي</a>
    <br/>

    {{template "content" .}}

    <br/>
    footer...

</body>
</html>
{{end}}

// templates/page-en.html
{{define "content"}}
Welcome
{{end}}

// templates/page-ar.html
{{define "content"}}
أهلا و سهلا
{{end}}

配置文件如下:

// configuration/en.yml
# Server configurations
server:
  host: "localhost"
  port: 8000

# Database credentials
database:
  user: "admin"
  pass: "password"

//  configuration/ar.yml
# تعريف الخادم
server:
  host: "localhost"
  port: 8000

# كلمة الس لقاعدة البيانات
database:
  user: "مدير"
  pass: "كلمة سر"

go.mod 文件是:

module hasan/web

go 1.16

require gopkg.in/yaml.v2 v2.4.0

更多关于Golang中如何实现服务器响应的双重返回的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

一个可能的原因是浏览器因为网站图标而请求了你的页面两次。乍一看,请求网站图标和页面本身调用了同一个处理程序。

更多关于Golang中如何实现服务器响应的双重返回的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


添加一个标签来识别打印的是哪个变量,例如:

fmt.Println("lang.Value=", lang.Value)
fmt.Println("UserName=", cfg.Database.Username)

在您的代码中,双重打印是由于浏览器对 /favicon.ico 的自动请求触发了两次 index 处理函数调用。浏览器在加载页面时会自动请求 favicon,而您的处理函数对所有路径(包括 /favicon.ico)都执行了相同的逻辑。

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

func index(w http.ResponseWriter, r *http.Request) {
    // 跳过 favicon.ico 请求
    if r.URL.Path == "/favicon.ico" {
        http.ServeFile(w, r, "./public/favicon.ico")
        return
    }
    
    var tmpl *template.Template
    var cfg Config
    lang, err := r.Cookie("language")
    if err != nil {
        readFile(&cfg, "en")
        tmpl, _ = template.New("").ParseFiles(fmt.Sprint("templates/en/page-en.html"), "base.html")
    } else {
        readFile(&cfg, lang.Value)
        fmt.Println(lang.Value)
        fmt.Println(cfg.Database.Username)
        tmpl, _ = template.New("").ParseFiles(fmt.Sprint("templates/", lang.Value, "/page-", lang.Value, ".html"), "base.html")
    }
    
    tmpl.ExecuteTemplate(w, "base", nil)
}

更好的做法是使用 http.FileServer 处理静态文件,并确保 favicon 文件存在于指定路径:

func main() {
    port := "8090"
    
    // 创建文件服务器处理静态文件
    fs := http.FileServer(http.Dir("./public"))
    http.Handle("/static/", http.StripPrefix("/static/", fs))
    http.Handle("/favicon.ico", fs)
    
    http.HandleFunc("/", index)
    fmt.Println("Listening to port:", port)
    error := http.ListenAndServe(":"+port, nil)
    fmt.Println(error)
}

同时确保在 ./public 目录下存在 favicon.ico 文件。

回到顶部