четверг, 25 июля 2019 г.

Пакет Gorilla mux: добавление промежуточного программного обеспечения (middleware)

Mux поддерживает добавление промежуточного программного обеспечения (middleware) к маршрутизатору (Router), который выполняется в порядке их добавления, если найдено совпадение, включая его подчиненные маршрутизаторы. Промежуточное программное обеспечение - это (как правило) небольшие куски кода, которые принимают один запрос, что-то с ним делают и передают другому промежуточному программному обеспечению или конечному обработчику. Некоторыми распространенными вариантами использования промежуточного программного обеспечения являются ведение журнала запросов, манипулирование заголовками или перехват ResponseWriter.

type MiddlewareFunc func(http.Handler) http.Handler

Как правило, возвращаемый обработчик является замыканием, которое делает что-то с переданными ему http.ResponseWriter и http.Request, а затем вызывает обработчик, переданный в качестве параметра в MiddlewareFunc (замыкания могут обращаться к переменным из контекста, в котором они созданы).

Простое базовое промежуточное программное обеспечение, которое регистрирует URI обрабатываемого запроса, может быть записано как:

func simpleMw(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // Делаем работу здесь
        log.Println(r.RequestURI)
        // Вызов следующего обработчика, 
        // который может быть другим промежуточным программным 
        // обеспечением в цепочке или конечным обработчиком.
        next.ServeHTTP(w, r)
    })
}

Промежуточное программное обеспечение (middleware) может быть добавлено к маршрутизатору с помощью Router.Use():

r := mux.NewRouter()
r.HandleFunc("/", handler)
r.Use(simpleMw)

Более сложное промежуточное программное обеспечение для аутентификации, которое сопоставляет токен сессии с пользователями, может быть записано как:

// Определим нашу структуру
type authenticationMiddleware struct {
    tokenUsers map[string]string
}

// Инициализируем где-нибудь
func (amw *authenticationMiddleware) Populate() {
    amw.tokenUsers["00000000"] = "user0"
    amw.tokenUsers["aaaaaaaa"] = "userA"
    amw.tokenUsers["05f717e5"] = "randomUser"
    amw.tokenUsers["deadbeef"] = "user0"
}

// Функция промежуточного программного обеспечения, 
// которая будет вызываться для каждого запроса
func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        token := r.Header.Get("X-Session-Token")

        if user, found := amw.tokenUsers[token]; found {
            // Мы нашли токен в нашей карте
            log.Printf("Authenticated user %s\n", user)
            next.ServeHTTP(w, r)
        } else {
            http.Error(w, "Forbidden", http.StatusForbidden)
        }
    })
}

r := mux.NewRouter()
r.HandleFunc("/", handler)

amw := authenticationMiddleware{tokenUsers: make(map[string]string)}
amw.Populate()

r.Use(amw.Middleware)

Примечание. Цепочка обработчиков будет остановлена, если ваше промежуточное программное обеспечение не вызовет next.ServeHTTP() с соответствующими параметрами. Это можно использовать для отмены запроса, если этого хочет автор промежуточного программного обеспечения.

Пример использования middleware с Gorilla mux:

package mux_test

import (
    "log"
    "net/http"

    "github.com/gorilla/mux"
)

// Определим нашу структуру
type authenticationMiddleware struct {
    tokenUsers map[string]string
}
// Инициализируем где-нибудь
func (amw *authenticationMiddleware) Populate() {
    amw.tokenUsers["00000000"] = "user0"
    amw.tokenUsers["aaaaaaaa"] = "userA"
    amw.tokenUsers["05f717e5"] = "randomUser"
    amw.tokenUsers["deadbeef"] = "user0"
}

// Функция промежуточного программного обеспечения, которая будет вызываться для каждого запроса
func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        token := r.Header.Get("X-Session-Token")

        if user, found := amw.tokenUsers[token]; found {
            // Мы нашли токен в нашей карте
            log.Printf("Authenticated user %s\n", user)
            next.ServeHTTP(w, r)
        } else {
            http.Error(w, "Forbidden", http.StatusForbidden)
        }
    })
}

func Example_authenticationMiddleware() {
    r := mux.NewRouter()
    r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        // Делаем что-то здесь
    })
    amw := authenticationMiddleware{make(map[string]string)}
    amw.Populate()
    r.Use(amw.Middleware)
}


Читайте также:


Комментариев нет:

Отправить комментарий