Golang模板错误处理:代码崩溃与未捕获异常问题分析

Golang模板错误处理:代码崩溃与未捕获异常问题分析

package main

import (
	"net/http"
	"github.com/satori/go.uuid"
	"html/template"
	"fmt"
)

type user struct{
	Email string
	First string
	Last string
}

var tpl *template.Template
var dbSessions = map[string]string{} 	// dbSessions 与会话ID和邮箱关联
var dbUsers = map[string]user{} 		// dbUsers 与邮箱和用户信息关联

func init(){
	tpl = template.Must(template.ParseGlob("templates/*.gohtml"))
}

func main(){
	http.HandleFunc("/", index)
	http.Handle("/favicon.ico", http.NotFoundHandler())
	http.ListenAndServe(":8080", nil)
}

func index (w http.ResponseWriter, req *http.Request){

	//查找Cookie,如果不存在则创建Cookie
	cookie, err := req.Cookie("session")
	if err != nil{
		id, _ := uuid.NewV4()
		cookie := &http.Cookie{
			Name: "session",
			Value: id.String(),
			HttpOnly: true,
			Path: "/",
		}
		http.SetCookie(w, cookie)
	}

	//创建用户变量
	var u user

	//检查会话ID(我们的Cookie值)是否已与邮箱关联
	//如果邮箱确实已存在
	//我们提取用户信息
	if thisVariableCouldBeAnything, ok := dbSessions[cookie.Value]; ok{
		u = dbUsers[thisVariableCouldBeAnything]
	}

	//处理表单提交并使用表单变量创建用户
	//使会话ID与此邮箱关联
	//使邮箱与此用户关联
	if req.Method == http.MethodPost{
		e := req.FormValue("email")
		f := req.FormValue("first")
		l := req.FormValue("last")
		u = user{e, f, l }

		dbSessions[cookie.Value] = e
		dbUsers[e] = u
	}

	//以用户作为数据执行模板
	tpl.ExecuteTemplate(w, "index.gohtml", u)
	fmt.Println(u)
}

更多关于Golang模板错误处理:代码崩溃与未捕获异常问题分析的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

确保你在模板中传入和访问的数据确实存在。ExecuteTemplate 会返回一个错误,你应该检查它。

更多关于Golang模板错误处理:代码崩溃与未捕获异常问题分析的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


阅读你的代码,如果首次交互是向服务器发送GET请求,那么你的用户对象将不会被创建。这意味着所有引用的模板字段都是空数据。

你可以通过以下方式解决这个问题:将创建用户的功能拆分到另一个仅处理POST请求的处理器中,并在将用户对象传入模板之前检查其中是否存在数据。

嗯,有意思,这是我的模板内容…

<!doctype html>

索引页面

{{if .First}} 邮箱:{{.Email}}

名字:{{.First}}

姓氏:{{.Last}} {{end}}

52 AM

我尝试检查错误,但仍然得到相同的结果

效果太棒了!你真是帮了大忙,非常感谢。

以下是 main.go 文件的最终代码(无需对 index.gohtml 做任何修改)…

package main
import (
	"net/http"
	"github.com/satori/go.uuid"
	"html/template"
	"fmt"
)
type user struct{
	Email string
	First string
	Last string
}
var tpl *template.Template
var dbSessions = map[string]string{} // dbSessions 关联会话ID和邮箱
var dbUsers = map[string]user{} // dbUsers 关联邮箱和用户信息
func init(){
	tpl = template.Must(template.ParseGlob("templates/*"))
}
func main(){
	http.HandleFunc("/", index)
	http.Handle("/favicon.ico", http.NotFoundHandler())
	http.ListenAndServe(":8080", nil)
}
func index (w http.ResponseWriter, req *http.Request){

cookie, err := req.Cookie("session")
if err != nil{
	id, _ := uuid.NewV4()
	cookie := &http.Cookie{
		Name: "session",
		Value: id.String(),
		HttpOnly: true,
		Path: "/",
	}
	http.SetCookie(w, cookie)
}

u := userData(w, req, cookie)

tpl.ExecuteTemplate(w, "index.gohtml", u)
fmt.Println(u)
}
func userData (w http.ResponseWriter, req *http.Request, cookie *http.Cookie) user{
var u user

if thisVariableCouldBeAnything, ok := dbSessions[cookie.Value]; ok{
	u = dbUsers[thisVariableCouldBeAnything]
}

if req.Method == http.MethodPost{
	e := req.FormValue("email")
	f := req.FormValue("first")
	l := req.FormValue("last")
	u = user{e, f, l }

	dbSessions[cookie.Value] = e
	dbUsers[e] = u
}
return u

在分析您提供的代码后,我发现了几个可能导致崩溃或未捕获异常的问题。以下是详细分析和修复方案:

主要问题分析

1. Cookie处理逻辑缺陷

当首次访问时,cookie变量在if块内创建,但在外部作用域未定义,导致后续代码访问cookie.Value时出现panic。

2. 模板执行错误未处理

tpl.ExecuteTemplate()的返回值未检查,模板渲染失败时会导致静默错误。

3. UUID生成错误未处理

uuid.NewV4()返回错误但被忽略。

修复后的代码

package main

import (
	"net/http"
	"html/template"
	"fmt"
	"log"

	"github.com/satori/go.uuid"
)

type user struct {
	Email string
	First string
	Last  string
}

var tpl *template.Template
var dbSessions = map[string]string{}
var dbUsers = map[string]user{}

func init() {
	tpl = template.Must(template.ParseGlob("templates/*.gohtml"))
}

func main() {
	http.HandleFunc("/", index)
	http.Handle("/favicon.ico", http.NotFoundHandler())
	log.Fatal(http.ListenAndServe(":8080", nil))
}

func index(w http.ResponseWriter, req *http.Request) {
	var cookie *http.Cookie
	var err error

	// 查找Cookie,如果不存在则创建Cookie
	cookie, err = req.Cookie("session")
	if err != nil {
		id, err := uuid.NewV4()
		if err != nil {
			http.Error(w, "无法生成会话ID", http.StatusInternalServerError)
			return
		}
		cookie = &http.Cookie{
			Name:     "session",
			Value:    id.String(),
			HttpOnly: true,
			Path:     "/",
		}
		http.SetCookie(w, cookie)
	}

	// 创建用户变量
	var u user

	// 检查会话ID是否已与邮箱关联
	if email, ok := dbSessions[cookie.Value]; ok {
		u = dbUsers[email]
	}

	// 处理表单提交
	if req.Method == http.MethodPost {
		e := req.FormValue("email")
		f := req.FormValue("first")
		l := req.FormValue("last")
		u = user{e, f, l}

		dbSessions[cookie.Value] = e
		dbUsers[e] = u
	}

	// 执行模板并处理错误
	err = tpl.ExecuteTemplate(w, "index.gohtml", u)
	if err != nil {
		http.Error(w, "模板渲染失败: "+err.Error(), http.StatusInternalServerError)
		return
	}
	
	fmt.Println(u)
}

关键修复点

  1. Cookie作用域修复:将cookie变量声明移到函数开头,确保在所有代码路径中都可访问。

  2. 错误处理增强

    • 处理uuid.NewV4()可能的错误
    • 检查并处理模板执行错误
    • 使用http.Error返回明确的错误信息
  3. 变量命名改进:将模糊的thisVariableCouldBeAnything改为有意义的email

  4. 启动错误处理:使用log.Fatal包装http.ListenAndServe以捕获启动错误。

这些修改确保了代码的健壮性,避免了潜在的panic和未处理的异常情况。

回到顶部