كيف تبني وسيطاً فعّالاً
الأجزاء المكوّنة
يتكون الوسيط عادةً من جزأين:
-
الجزء الأول يُنفذ مرة واحدة، عند تهيئة الوسيط. هنا تُعدّ الكائنات العامة ومنطق التكوين وغيرها — كل ما يحتاج للحدوث مرة واحدة فقط في عمر التطبيق.
-
الجزء الثاني يُنفذ مع كل طلب. على سبيل المثال، في وسيط قاعدة البيانات، ستحقن كائن قاعدة البيانات العام في سياق الطلب. بمجرد وجوده في السياق، يمكن للوسيطات الأخرى ودوال المعالجة استرداده واستخدامه.
func funcName(params string) gin.HandlerFunc { // <--- // This is part one // ---> // Example initialization: validate input params if err := check(params); err != nil { panic(err) }
return func(c *gin.Context) { // <--- // This is part two // ---> // Example execution per request: inject into context c.Set("TestVar", params) c.Next() }}عملية التنفيذ
لنلقِ نظرة على كود المثال التالي:
func main() { router := gin.Default()
router.Use(globalMiddleware())
router.GET("/rest/n/api/*some", mid1(), mid2(), handler)
router.Run()}
func globalMiddleware() gin.HandlerFunc { fmt.Println("globalMiddleware...1")
return func(c *gin.Context) { fmt.Println("globalMiddleware...2") c.Next() fmt.Println("globalMiddleware...3") }}
func handler(c *gin.Context) { fmt.Println("exec handler.")}
func mid1() gin.HandlerFunc { fmt.Println("mid1...1")
return func(c *gin.Context) {
fmt.Println("mid1...2") c.Next() fmt.Println("mid1...3") }}
func mid2() gin.HandlerFunc { fmt.Println("mid2...1")
return func(c *gin.Context) { fmt.Println("mid2...2") c.Next() fmt.Println("mid2...3") }}وفقاً لقسم الأجزاء المكوّنة أعلاه، عند تشغيل عملية Gin، يُنفذ الجزء الأول من كل وسيط أولاً ويطبع المعلومات التالية:
globalMiddleware...1mid1...1mid2...1ترتيب التهيئة هو:
globalMiddleware...1 | vmid1...1 | vmid2...1عند إجراء طلب — مثل curl -v localhost:8080/rest/n/api/some — يُنفذ الجزء الثاني من كل وسيط بالترتيب وينتج المخرجات التالية:
globalMiddleware...2mid1...2mid2...2exec handler.mid2...3mid1...3globalMiddleware...3بعبارة أخرى، ترتيب التنفيذ هو:
globalMiddleware...2 | vmid1...2 | vmid2...2 | vexec handler. | vmid2...3 | vmid1...3 | vglobalMiddleware...3