Skip to main content

Phát Triển Web với Go - Xây Dựng Ứng Dụng Web! 🌐

Chào mừng bạn đến với bài học về phát triển web trong Go! Trong bài học này, chúng ta sẽ tìm hiểu cách xây dựng các ứng dụng web mạnh mẽ và hiệu quả với Go.

HTTP Server Cơ Bản 🚀

1. Server Đơn Giản

func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Xin chào, Thế giới!")
})

http.ListenAndServe(":8080", nil)
}

💡 Giải thích:

  • Tạo server HTTP cơ bản
  • Xử lý request đến "/"
  • Chạy trên port 8080

2. Server với Mux

func main() {
mux := http.NewServeMux()

mux.HandleFunc("/", handleHome)
mux.HandleFunc("/about", handleAbout)

http.ListenAndServe(":8080", mux)
}

💡 Giải thích:

  • Sử dụng router
  • Xử lý nhiều đường dẫn
  • Code tổ chức tốt hơn

Routing 🛣️

1. Routing Cơ Bản

func handleHome(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
fmt.Fprintf(w, "Chào mừng đến với trang chủ!")
}

💡 Giải thích:

  • Kiểm tra đường dẫn
  • Xử lý 404
  • Trả về nội dung

2. RESTful Routing

func handleUsers(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
getUsers(w, r)
case http.MethodPost:
createUser(w, r)
default:
http.Error(w, "Phương thức không được phép", http.StatusMethodNotAllowed)
}
}

💡 Giải thích:

  • Xử lý HTTP methods
  • RESTful API
  • Code sạch và rõ ràng

Middleware 🔄

1. Middleware Tùy Chỉnh

func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()

next.ServeHTTP(w, r)

log.Printf("%s %s %v", r.Method, r.URL.Path, time.Since(start))
})
}

💡 Giải thích:

  • Ghi log request
  • Đo thời gian xử lý
  • Dễ dàng mở rộng

2. Chuỗi Middleware

func chain(handlers ...http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
for _, h := range handlers {
h.ServeHTTP(w, r)
}
})
}

💡 Giải thích:

  • Kết hợp nhiều middleware
  • Xử lý theo thứ tự
  • Code linh hoạt

Xử Lý Request 📝

1. Xử Lý Form Data

func handleForm(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodPost {
err := r.ParseForm()
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

name := r.FormValue("name")
email := r.FormValue("email")

// Xử lý dữ liệu form
}
}

💡 Giải thích:

  • Đọc form data
  • Xử lý lỗi
  • Lấy giá trị form

2. Xử Lý JSON

type User struct {
Name string `json:"name"`
Email string `json:"email"`
}

func handleJSON(w http.ResponseWriter, r *http.Request) {
var user User
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

// Xử lý dữ liệu user
}

💡 Giải thích:

  • Đọc JSON
  • Chuyển đổi struct
  • Xử lý lỗi

Xử Lý Response 📤

1. Trả Về JSON

func sendJSON(w http.ResponseWriter, data interface{}) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(data)
}

💡 Giải thích:

  • Set header
  • Mã hóa JSON
  • Trả về response

2. Render Template

func renderTemplate(w http.ResponseWriter, tmpl string, data interface{}) {
templates := template.Must(template.ParseFiles("templates/" + tmpl + ".html"))
templates.Execute(w, data)
}

💡 Giải thích:

  • Đọc template
  • Truyền dữ liệu
  • Render HTML

Kết Nối Database 💾

1. Kết Nối Database

func initDB() (*sql.DB, error) {
db, err := sql.Open("postgres", "postgres://user:password@localhost/dbname?sslmode=disable")
if err != nil {
return nil, err
}

if err := db.Ping(); err != nil {
return nil, err
}

return db, nil
}

💡 Giải thích:

  • Kết nối database
  • Kiểm tra kết nối
  • Xử lý lỗi

2. Truy Vấn Database

func getUsers(db *sql.DB) ([]User, error) {
rows, err := db.Query("SELECT id, name, email FROM users")
if err != nil {
return nil, err
}
defer rows.Close()

var users []User
for rows.Next() {
var user User
if err := rows.Scan(&user.ID, &user.Name, &user.Email); err != nil {
return nil, err
}
users = append(users, user)
}

return users, nil
}

💡 Giải thích:

  • Thực thi query
  • Đọc kết quả
  • Xử lý lỗi

Xác Thực 🔐

1. Xác Thực Cơ Bản

func basicAuth(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
username, password, ok := r.BasicAuth()
if !ok {
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
http.Error(w, "Không được phép", http.StatusUnauthorized)
return
}

if !checkCredentials(username, password) {
http.Error(w, "Không được phép", http.StatusUnauthorized)
return
}

next.ServeHTTP(w, r)
}
}

💡 Giải thích:

  • Kiểm tra credentials
  • Xác thực người dùng
  • Bảo vệ route

2. Xác Thực JWT

func generateToken(user User) (string, error) {
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"user_id": user.ID,
"exp": time.Now().Add(time.Hour * 24).Unix(),
})

return token.SignedString([]byte("secret"))
}

💡 Giải thích:

  • Tạo token JWT
  • Thêm claims
  • Ký token

Quản Lý Phiên 🔑

1. Xử Lý Phiên

type Session struct {
ID string
UserID string
ExpiresAt time.Time
}

func createSession(userID string) (*Session, error) {
session := &Session{
ID: uuid.New().String(),
UserID: userID,
ExpiresAt: time.Now().Add(24 * time.Hour),
}

// Lưu phiên vào database
return session, nil
}

💡 Giải thích:

  • Tạo phiên mới
  • Lưu thông tin
  • Quản lý thời gian

2. Middleware Phiên

func sessionMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
sessionID, err := r.Cookie("session_id")
if err != nil {
http.Redirect(w, r, "/login", http.StatusSeeOther)
return
}

session, err := getSession(sessionID.Value)
if err != nil {
http.Redirect(w, r, "/login", http.StatusSeeOther)
return
}

ctx := context.WithValue(r.Context(), "session", session)
next.ServeHTTP(w, r.WithContext(ctx))
})
}

💡 Giải thích:

  • Kiểm tra phiên
  • Chuyển hướng
  • Lưu vào context

Xử Lý Lỗi ⚠️

1. Xử Lý Lỗi Tùy Chỉnh

func handleError(w http.ResponseWriter, err error, status int) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(map[string]string{
"error": err.Error(),
})
}

💡 Giải thích:

  • Trả về lỗi JSON
  • Set status code
  • Thông báo rõ ràng

2. Khôi Phục Panic

func recoverMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
log.Printf("Panic: %v", err)
http.Error(w, "Lỗi server", http.StatusInternalServerError)
}
}()
next.ServeHTTP(w, r)
})
}

💡 Giải thích:

  • Bắt panic
  • Ghi log
  • Trả về lỗi

Best Practices (Cách sử dụng tốt nhất) ✅

  1. Xử lý lỗi

    // ✅ Đúng
    if err != nil {
    handleError(w, err, http.StatusBadRequest)
    return
    }

    // ❌ Sai
    // Bỏ qua lỗi
  2. Middleware

    // ✅ Đúng
    mux := http.NewServeMux()
    mux.Handle("/", loggingMiddleware(authMiddleware(handleHome)))

    // ❌ Sai
    // Không sử dụng middleware
  3. Xử lý request

    // ✅ Đúng
    if r.Method != http.MethodPost {
    http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
    return
    }

    // ❌ Sai
    // Không kiểm tra method
  4. Database

    // ✅ Đúng
    defer rows.Close()
    if err != nil {
    return nil, fmt.Errorf("database error: %v", err)
    }

    // ❌ Sai
    // Không đóng kết nối

Tiếp theo 🎯

Trong các bài học tiếp theo, chúng ta sẽ:

  • Tìm hiểu về design patterns
  • Học cách tối ưu hiệu suất
  • Khám phá các kỹ thuật nâng cao
  • Thực hành với các dự án thực tế

💡 Lời khuyên: Hãy bắt đầu với những thứ cơ bản và dần dần xây dựng lên. Đừng quên viết test và xử lý lỗi một cách cẩn thận!