Middleware, nhân tố mới xuất hiện trong framework. Middleware là cái gì? Tại sao lại thêm vào đây? Thêm vào ntn?

Mô hình chúng ta đang có là ntn.
MVC

Hãy tưởng tượng ntn, bạn rất giỏi trong việc nấu cơm bằng nồi cơm điện. Không ai có thể nấu cơm bằng nồi cơm điện ngon hơn bạn. Bạn quyết định cung cấp dịch vụ nấu cơm bằng nồi cơm điện. Bạn đặt hàng thằng Router là cứ ai yêu cầu nấu cái gì đó thì chuyển hết cho bạn, vì chỉ có bạn cung cấp dịch vụ nấu.

Đời không như là mơ. Khách hàng không chỉ yêu cầu nấu cơm, ngoài các yêu cầu nấu cơm bình thường, thỉnh thoảng lại có các yêu cầu như:

  • Nấu canh đi em ơi.
  • Nấu cháo có đc ko.
  • Nấu cơm đừng cho nước nhé.
  • Nấu cơm bằng bột mỳ đi, đang cần gấp.
  • Nấu cơm bằng chảo đi, ngon lắm.

Và bạn cũng muốn bỏ qua các yêu cầu vô duyên, vô lý, chả liên quan, muốn ghi nhật ký lại khi xủ lí yêu cầu, … Bạn chỉ muốn nhận các yêu cầu “sạch sẽ” là nấu cơm bằng nồi cơm điện, còn những thứ khác thì cứ để ai đó lo. Và thế là middleware ra đời.
MVC

Để hiểu tại sao middleware lại ngoằng từ trước controller đến sau View, nó có dạng như hình sau
Middleaware

Application chính là dịch vụ nấu cơm của bạn. Do Middleware bao quanh cả application nên:

  • Nếu xử lí trong middle ở phía trước app như: Kiểm tra có phải nấu cơm ko, có dùng nồi cơm điện ko, … gọi là before middleware.
  • Nếu xử lí trong middleware dienx ra sau app như: Kiểm tra cơm có nát ko, … gọi là after middleware.
  • Nếu xử lí ở cả trước, sau app như: ghi nhật kí thời gian bắt đầu, kết thúc nấu, .. gọi là gì mình cũng ko biết :p

Cách thêm middleware trong framework của mình:

Code middleware

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package middleware

import (
"log"
"net/http"
"time"
)

func LoggingHandler(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
t1 := time.Now() // chạy trước nấu cơm
next.ServeHTTP(w, r) // gọi đến middleware tiếp theo hoặc nấu cơm
t2 := time.Now() // chạy sau nấu cơm
log.Printf("[%s] %q %v\n", r.Method, r.URL.String(), t2.Sub(t1))
}

return http.HandlerFunc(fn)
}

Thêm vào Router

1
2
commonHandlers := core.Middleware(middleware.LoggingHandler)
core.Routes.AddRoute("/id/{id}", "get", commonHandlers.ThenFunc(controller.Test.Asd))