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) ✅
-
Xử lý lỗi
// ✅ Đúng
if err != nil {
handleError(w, err, http.StatusBadRequest)
return
}
// ❌ Sai
// Bỏ qua lỗi -
Middleware
// ✅ Đúng
mux := http.NewServeMux()
mux.Handle("/", loggingMiddleware(authMiddleware(handleHome)))
// ❌ Sai
// Không sử dụng middleware -
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 -
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!