Let's Go میان‌افزار › نحوه کار میان‌افزار
قبلی · فهرست · بعدی
فصل ۶.۱

نحوه کار میان‌افزار (How Middleware Works)

پیش‌تر در کتاب مطلبی را گفتم که می‌خواهم در این فصل آن را گسترش دهم:

"می‌توانید یک برنامه وب Go را به عنوان زنجیره‌ای از متدهای ServeHTTP() در نظر بگیرید که یکی پس از دیگری فراخوانی می‌شوند."

در حال حاضر، در برنامه ما، وقتی سرور یک درخواست HTTP جدید دریافت می‌کند، متد ServeHTTP() مربوط به servemux را فراخوانی می‌کند. این متد بر اساس متد درخواست و مسیر URL، هندلر مربوطه را پیدا کرده و به نوبه خود متد ServeHTTP() آن هندلر را فراخوانی می‌کند.

ایده اصلی میان‌افزار، وارد کردن یک هندلر دیگر در این زنجیره است. هندلر میان‌افزار منطقی را اجرا می‌کند، مانند ثبت یک درخواست، و سپس متد ServeHTTP() هندلر بعدی را در زنجیره فراخوانی می‌کند.

در واقع، ما در حال حاضر از یک میان‌افزار در برنامه‌مان استفاده می‌کنیم - تابع http.StripPrefix() از سرو فایل‌های استاتیک، که پیشوند خاصی را از مسیر URL درخواست قبل از ارسال درخواست به فایل سرور حذف می‌کند.

الگو

الگوی استاندارد برای ایجاد میان‌افزار خودتان به این شکل است:

func myMiddleware(next http.Handler) http.Handler {
    fn := func(w http.ResponseWriter, r *http.Request) {
        // TODO: Execute our middleware logic here...
        next.ServeHTTP(w, r)
    }

    return http.HandlerFunc(fn)
}

کد خودش نسبتاً مختصر است، اما نکات زیادی برای درک در آن وجود دارد.

اگر این موضوع گیج‌کننده به نظر می‌رسد، می‌توانید ساده‌تر به آن فکر کنید: myMiddleware() تابعی است که هندلر بعدی را در یک زنجیره به عنوان پارامتر می‌پذیرد. این تابع یک هندلر را برمی‌گرداند که منطقی را اجرا کرده و سپس هندلر بعدی را فراخوانی می‌کند.

ساده‌سازی میان‌افزار

یک تغییر در این الگو، استفاده از تابع بی‌نام در داخل میان‌افزار myMiddleware() است، به این صورت:

func myMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // TODO: Execute our middleware logic here...
        next.ServeHTTP(w, r)
    })
}

این الگو در دنیای واقعی بسیار رایج است و احتمالاً اگر کد منبع برنامه‌های دیگر یا پکیج‌های شخص ثالث را می‌خوانید، بیشتر با این الگو مواجه خواهید شد.

موقعیت‌دهی میان‌افزار

مهم است توضیح دهیم که موقعیت میان‌افزار در زنجیره هندلرها بر رفتار برنامه شما تأثیر خواهد گذاشت.

اگر میان‌افزار خود را قبل از servemux در زنجیره قرار دهید، روی هر درخواستی که برنامه شما دریافت می‌کند تأثیر خواهد گذاشت.

myMiddleware → servemux → application handler

مثال خوبی از جایی که این مورد مفید خواهد بود، میان‌افزار برای ثبت درخواست‌ها است - زیرا این معمولاً چیزی است که می‌خواهید برای تمام درخواست‌ها انجام دهید.

به طور جایگزین، می‌توانید میان‌افزار را بعد از servemux در زنجیره قرار دهید - با پوشاندن یک هندلر برنامه خاص. این باعث می‌شود میان‌افزار شما فقط برای یک مسیر خاص اجرا شود.

servemux → myMiddleware → application handler

مثالی از این مورد می‌تواند میان‌افزار احراز هویت باشد که ممکن است بخواهید فقط روی مسیرهای خاصی اجرا شود.

همانطور که در طول کتاب پیش می‌رویم، نحوه انجام هر دوی این موارد را در عمل نشان خواهیم داد.

واژه‌نامه اصطلاحات فنی

اصطلاح فارسی معادل انگلیسی توضیح
میان‌افزار Middleware کدی که بین درخواست و پاسخ HTTP اجرا می‌شود
تابع بسته‌بندی Wrapper Function تابعی که یک تابع دیگر را دریافت و تغییر می‌دهد
هندلر HTTP HTTP Handler تابعی که درخواست‌های HTTP را پردازش می‌کند
میان‌افزار ثبت Logging Middleware میان‌افزاری که درخواست‌ها را ثبت می‌کند
زنجیره‌های میان‌افزار Middleware Chains ترکیب چندین میان‌افزار به صورت پشت سر هم
مسیریاب Router بخشی که درخواست‌ها را به هندلرها هدایت می‌کند
پردازش درخواست Request Processing عملیات انجام شده روی درخواست‌های دریافتی
پاسخ‌دهنده Response Writer ابزاری برای نوشتن پاسخ HTTP
درخواست‌دهنده Request شیء حاوی اطلاعات درخواست HTTP
مدیریت مسیر Route Handling پردازش درخواست‌ها بر اساس مسیر URL