تطوير خوادم الويب في Golang - من البسيط إلى المعقد

تطوير خوادم الويب في Golang - من البسيط إلى المعقد

منذ خمس سنوات بدأت تطوير Gophish، جعل هذا من الممكن تعلم Golang. أدركت أن Go هي لغة قوية ، تكملها العديد من المكتبات. Go متعدد الاستخدامات: على وجه الخصوص ، يمكنك بسهولة تطوير التطبيقات من جانب الخادم معه.

تتناول هذه المقالة كتابة خادم في Go. لنبدأ بأشياء بسيطة مثل "Hello world!" وننتهي مع تطبيق بهذه الميزات:

- استخدام Let's Encrypt لـ HTTPS.
- العمل كجهاز توجيه API.
- العمل مع البرامج الوسيطة.
- التعامل مع الملفات الثابتة.
- الاغلاق الصحيح.

يوصي Skillbox بما يلي: دورة عملية "مطور Python من البداية".

نذكر: لجميع قراء "Habr" - خصم 10 روبل عند التسجيل في أي دورة Skillbox باستخدام رمز "Habr" الترويجي.

مرحبا العالم!

يمكن أن يكون إنشاء خادم ويب في Go سريعًا جدًا. فيما يلي مثال على استخدام معالج يقوم بإرجاع عبارة "Hello، world!" الموعودة أعلاه.

package main
 
import (
"fmt"
"net/http"
)
 
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World!")
})
http.ListenAndServe(":80", nil)
}

بعد ذلك ، إذا قمت بتشغيل التطبيق وفتح الصفحة مؤسسة الكوثر، فسترى على الفور النص "Hello، world!" (بالطبع ، إذا كان كل شيء يعمل بشكل صحيح).

سنستخدم المعالج بشكل متكرر في ما يلي ، لكن دعنا أولاً نفهم كيف يعمل كل شيء.

صافي/http

استخدم المثال الحزمة net/http، هي الأداة الأساسية لـ Go لتطوير كل من الخوادم وعملاء HTTP. لفهم الكود ، دعنا نفهم معنى ثلاثة عناصر مهمة: http.Handler و http.ServeMux و http.Server.

معالجات HTTP

عندما نتلقى طلبًا ، يقوم المعالج بتحليله وإنشاء استجابة. يتم تنفيذ المعالجات في Go على النحو التالي:

type Handler interface {
        ServeHTTP(ResponseWriter, *Request)
}

يستخدم المثال الأول الدالة المساعدة http.HandleFunc. إنه يلف وظيفة أخرى والتي بدورها تقبل http.ResponseWriter و http.Request في ServeHTTP.

بمعنى آخر ، يتم تمثيل المعالجات في Golang بواجهة واحدة ، مما يوفر الكثير من الفرص للمبرمج. لذلك ، على سبيل المثال ، يتم تنفيذ البرامج الوسيطة باستخدام معالج ، حيث يقوم ServeHTTP أولاً بشيء ما ثم يستدعي طريقة ServeHTTP لمعالج آخر.

كما ذكر أعلاه ، يقوم المتعاملون ببساطة بتشكيل ردود على الطلبات. ولكن أي معالج يجب استخدامه في وقت معين؟

طلب التوجيه

من أجل اتخاذ القرار الصحيح ، استخدم مُضاعِف HTTP. في عدد من المكتبات يطلق عليه muxer أو router ، لكنهم جميعًا متماثلون. تتمثل وظيفة معدد الإرسال في تحليل مسار الطلب وتحديد المعالج المناسب.

إذا كنت بحاجة إلى دعم للتوجيه المعقد ، فمن الأفضل استخدام مكتبات الطرف الثالث. واحدة من الأكثر تقدما غوريلا / مسك и اذهب تشي / تشي، تتيح هذه المكتبات إمكانية تنفيذ المعالجة الوسيطة دون أي مشاكل. بمساعدتهم ، يمكنك إعداد توجيه أحرف البدل وتنفيذ عدد من المهام الأخرى. ميزتها هي التوافق مع معالجات HTTP القياسية. نتيجة لذلك ، يمكنك كتابة تعليمات برمجية بسيطة يمكن تعديلها في المستقبل.

لن يتطلب العمل مع أطر عمل معقدة في الوضع الطبيعي حلولًا قياسية تمامًا ، وهذا يعقد بشكل كبير استخدام المعالجات الافتراضية. سيكون الجمع بين المكتبة الافتراضية وجهاز توجيه بسيط كافياً لإنشاء الغالبية العظمى من التطبيقات.

معالجة الاستعلام

بالإضافة إلى ذلك ، نحتاج إلى مكون "يستمع" للاتصالات الواردة ويعيد توجيه جميع الطلبات إلى المعالج الصحيح. يمكن لـ http.Server التعامل بسهولة مع هذه المهمة.

يوضح ما يلي أن الخادم مسؤول عن جميع المهام المتعلقة بمعالجة الاتصالات. هذا ، على سبيل المثال ، العمل على بروتوكول TLS. يتم استخدام خادم HTTP قياسي لتنفيذ استدعاء http.ListenAndServer.

الآن دعونا نلقي نظرة على أمثلة أكثر تعقيدًا.

مضيفا دعونا تشفير

بشكل افتراضي ، يعمل تطبيقنا عبر بروتوكول HTTP ، لكن يوصى باستخدام بروتوكول HTTPS. في Go ، يمكن القيام بذلك دون مشاكل. إذا تلقيت شهادة ومفتاح خاص ، يكفي أن تكتب ListenAndServeTLS بالشهادة الصحيحة وملفات المفتاح.

http.ListenAndServeTLS(":443", "cert.pem", "key.pem", nil)

يمكنك دائما أن تفعل ما هو أفضل.

دعونا تشفير يمنح شهادات مجانية مع إمكانية التجديد التلقائي. من أجل استخدام الخدمة ، تحتاج إلى حزمة autocert.

أسهل طريقة لإعداده هي استخدام طريقة autocert.NewListener مع http.Serve. تسمح لك الطريقة باستلام وتجديد شهادات TLS أثناء معالجة خادم HTTP للطلبات:

http.Serve(autocert.NewListener("example.com"), nil)

إذا فتحنا في المتصفح example.com، نحصل على استجابة HTTPS "Hello، world!".

إذا كنت بحاجة إلى تكوين أكثر تفصيلاً ، فيجب عليك استخدام autocert.Manager. ثم نقوم بإنشاء مثيل http.Server الخاص بنا (حتى الآن استخدمناه افتراضيًا) وأضفنا المدير إلى خادم TLSConfig:

m := &autocert.Manager{
Cache:      autocert.DirCache("golang-autocert"),
Prompt:     autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist("example.org", "www.example.org"),
}
server := &http.Server{
    Addr:      ":443",
    TLSConfig: m.TLSConfig(),
}
server.ListenAndServeTLS("", "")

هذه طريقة سهلة لتنفيذ دعم HTTPS الكامل مع التجديد التلقائي للشهادة.

إضافة مسارات مخصصة

جهاز التوجيه الافتراضي المتضمن في المكتبة القياسية جيد ، لكنه أساسي للغاية. تحتاج معظم التطبيقات إلى توجيه أكثر تعقيدًا ، بما في ذلك المسارات المتداخلة وحروف البدل ، أو تعيين الأنماط ومعلمات المسار.

في هذه الحالة ، يجب عليك استخدام الحزم غوريلا / مسك и اذهب تشي / تشي. سوف نتعلم كيفية العمل مع الأخير - يظهر مثال أدناه.

معطى ملف api / v1 / api.go الذي يحتوي على مسارات API الخاصة بنا:

/ HelloResponse is the JSON representation for a customized message
type HelloResponse struct {
Message string `json:"message"`
}
 
// HelloName returns a personalized JSON message
func HelloName(w http.ResponseWriter, r *http.Request) {
name := chi.URLParam(r, "name")
response := HelloResponse{
Message: fmt.Sprintf("Hello %s!", name),
}
jsonResponse(w, response, http.StatusOK)
}
 
// NewRouter returns an HTTP handler that implements the routes for the API
func NewRouter() http.Handler {
r := chi.NewRouter()
r.Get("/{name}", HelloName)
return r
}

قمنا بتعيين بادئة api / vq للمسارات في الملف الرئيسي.

يمكننا بعد ذلك تحميل هذا على جهاز التوجيه الرئيسي الخاص بنا تحت api / v1 / البادئة مرة أخرى في تطبيقنا الرئيسي:

// NewRouter returns a new HTTP handler that implements the main server routes
func NewRouter() http.Handler {
router := chi.NewRouter()
    router.Mount("/api/v1/", v1.NewRouter())
    return router
}
http.Serve(autocert.NewListener("example.com"), NewRouter())

تجعل سهولة العمل مع المسارات المعقدة في Go من الممكن تبسيط هيكلة وصيانة التطبيقات المعقدة الكبيرة.

العمل مع البرامج الوسيطة

في حالة المعالجة الوسيطة ، يتم استخدام التفاف معالج HTTP بآخر ، مما يجعل من الممكن إجراء المصادقة والضغط والتسجيل وبعض الوظائف الأخرى بسرعة.

على سبيل المثال ، دعنا نفكر في واجهة http.Handler ، بمساعدتها سنكتب معالجًا مع مصادقة مستخدمي الخدمة.

func RequireAuthentication(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        if !isAuthenticated(r) {
            http.Redirect(w, r, "/login", http.StatusTemporaryRedirect)
            return
        }
        // Assuming authentication passed, run the original handler
        next.ServeHTTP(w, r)
    })
}

هناك أجهزة توجيه تابعة لجهات خارجية ، مثل chi ، تتيح لك توسيع وظائف المعالجة الوسيطة.

العمل مع الملفات الثابتة

تتضمن مكتبة Go القياسية مرافق للعمل مع المحتوى الثابت ، بما في ذلك الصور ، بالإضافة إلى ملفات JavaScript و CSS. يمكن الوصول إليها من خلال وظيفة http.FileServer. تقوم بإرجاع معالج يقوم بتوزيع الملفات من دليل معين.

func NewRouter() http.Handler {
    router := chi.NewRouter()
    r.Get("/{name}", HelloName)
 
// Настройка раздачи статических файлов
staticPath, _ := filepath.Abs("../../static/")
fs := http.FileServer(http.Dir(staticPath))
    router.Handle("/*", fs)
    
    return r

تأكد من تذكر أن http.Dir يعرض محتويات الدليل إذا لم يكن يحتوي على ملف index.html الرئيسي. في هذه الحالة ، من أجل منع اختراق الدليل ، يجب عليك استخدام الحزمة unindexed.

الاغلاق الصحيح

يحتوي Go أيضًا على ميزة مثل الإغلاق الرشيق لخادم HTTP. يمكن القيام بذلك باستخدام طريقة إيقاف التشغيل (). يتم تشغيل الخادم في goroutine ، ثم يتم الاستماع إلى القناة لاستقبال إشارة المقاطعة. بمجرد تلقي الإشارة ، يتم إيقاف تشغيل الخادم ، ولكن ليس على الفور ، ولكن بعد بضع ثوانٍ.

handler := server.NewRouter()
srv := &http.Server{
    Handler: handler,
}
 
go func() {
srv.Serve(autocert.NewListener(domains...))
}()
 
// Wait for an interrupt
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
<-c
 
// Attempt a graceful shutdown
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
srv.Shutdown(ctx)

وختاما

Go هي لغة قوية مع مكتبة قياسية عالمية تقريبًا. قدراته الافتراضية واسعة جدًا ، ويمكنك تقويتها بمساعدة الواجهات - وهذا يسمح لك بتطوير خوادم HTTP موثوقة حقًا.

يوصي Skillbox بما يلي:

المصدر: www.habr.com

إضافة تعليق