Thông báo lỗiBạn làm mới ứng dụng web Go của mình, mong đợi một bảng điều khiển được cá nhân hóa, nhưng thay vào đó lại gặp lỗi 500. Kiểm tra nhật ký (logs) sẽ thấy lỗi cụ thể sau:
template: mytemplate:5:8: executing "mytemplate" at : can't evaluate field Username in type main.User
Điều này xảy ra vì engine template đã cố gắng truy cập vào một phần dữ liệu mà nó không thể nhìn thấy. Thông thường, nguyên nhân là do một trường riêng tư (private field) hoặc hiểu sai về cách ngữ cảnh "dấu chấm" (dot context) thay đổi trong quá trình thực thi.
Nguyên nhân gốc rễ: Trường Exported và UnexportedCác quy tắc về khả năng hiển thị trong Go rất đơn giản: chữ hoa là công khai (exported), chữ thường là riêng tư (unexported). Gói html/template sử dụng reflection để đọc các struct của bạn trong thời gian chạy. Tuy nhiên, reflection không thể vượt qua tính bảo mật của Go để truy cập các trường riêng tư.
Hãy tưởng tượng struct của bạn trông như thế này:
type User struct {
username string // Riêng tư (Private)
Email string // Công khai (Public)
}
Ngay cả khi bạn truyền dữ liệu chính xác, {{.username}} vẫn sẽ thất bại. Engine coi các trường riêng tư như thể chúng không tồn tại.
Cách sửa lỗi### 1. Viết hoa các trường trong StructCách khắc phục nhanh nhất là thay đổi định nghĩa struct của bạn. Đảm bảo mọi trường được sử dụng trong template đều bắt đầu bằng một chữ cái viết hoa.
type User struct {
Username string
Email string
}
Cập nhật template của bạn cho khớp: <p>Xin chào, {{.Username}}!</p>. Thay đổi đơn giản này giải quyết được 90% các lỗi loại này.
2. Làm chủ ngữ cảnh "Dấu chấm" (Dot Context)"Dấu chấm" (.) đại diện cho con trỏ hiện tại của bạn. Nó thay đổi khi bạn vào một khối {{range}} hoặc {{with}}. Nếu bạn lặp qua một danh sách các bài viết, dấu chấm không còn là dữ liệu cấp cao nhất của bạn nữa; nó trở thành bài viết cụ thể mà bạn đang xử lý.
{{range .Posts}}
<p>Đăng bởi: {{.User.Username}}</p> <!-- Đoạn này thường thất bại! -->
{{end}}
Nếu User là một thuộc tính của dữ liệu toàn cục chứ không phải của struct Post, template sẽ bị lỗi. Hãy sử dụng $ để quay lại gốc dữ liệu ban đầu được truyền vào template:
{{range .Posts}}
<li>Được viết bởi: {{$.User.Username}}</li> <!-- Cách này hoạt động! -->
{{end}}
3. Kiểm tra tính phân biệt chữ hoa chữ thườngGo rất khắt khe với việc phân biệt chữ hoa chữ thường. Nếu struct của bạn định nghĩa Username nhưng template HTML gọi {{.UserName}} (lưu ý chữ 'N' viết hoa), việc đánh giá sẽ thất bại ngay lập tức. Go template không cung cấp tính năng "khớp mờ" (fuzzy matching) cho tên trường.
Xác minh cách sửa lỗiĐừng khởi động lại toàn bộ máy chủ chỉ để kiểm tra một lỗi nhỏ. Hãy sử dụng một script độc lập nhanh chóng để xác nhận template được parse và thực thi chính xác.
package main
import (
"html/template"
"os"
)
type User struct {
Username string
}
func main() {
const doc = `<p>Xin chào, {{.Username}}!</p>`
t := template.Must(template.New("test").Parse(doc))
// Kiểm tra với dữ liệu thực tế
err := t.Execute(os.Stdout, User{Username: "Alice"})
if err != nil {
panic(err)
}
}

