Определенные конечные точки ограничения скорости

Я новичок в GoLang и работаю над своим первым API. У меня есть две конечные точки, и я хочу ограничить скорость только для одной из них. Я нашел полезный учебник, чтобы начать работу, и я основал свой подход на нем, понимая, что этот подход будет ограничивать обе мои конечные точки:

var limiter = rate.NewLimiter(rate.Every((1*time.Hour)/3), 1)

func limit(next http.Handler) http.Handler {
    return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
        if limiter.Allow() == false {
            http.Error(res, http.StatusText(429), http.StatusTooManyRequests)
            return
        }
        next.ServeHTTP(res, req)
    })
}

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", createNewToken)
    mux.HandleFunc("/notify", sendPushNotificationToAllTokens)

    log.Fatal(http.ListenAndServeTLS(":5050", "localhost.crt", "localhost.key", limit(mux)))
}

Я исследовал разницу между http.Handle и http.HandleFunc и наивно полагал, что смогу заменить http.HandleFunc на http.Handle. Этот подход полностью ошибочен, поскольку логика, содержащаяся в HandlerFunc, никогда не выполняется:

var limiter = rate.NewLimiter(rate.Every(1*time.Hour/3), 1)

func limit(next http.HandlerFunc) http.HandlerFunc {
    return func(res http.ResponseWriter, req *http.Request) {
        if limiter.Allow() == false {
            http.Error(res, http.StatusText(429), http.StatusTooManyRequests)
            return
        }
        next.ServeHTTP(res, req)
    }
}

func main() {
    //mux := http.NewServeMux()
    http.HandleFunc("/", createNewToken)
    http.HandleFunc("/notify", sendPushNotificationToAllTokens)

    // attempt to only rate limit the /notify endpoint 
    log.Fatal(http.ListenAndServeTLS(":5050", "localhost.crt", "localhost.key", limit(sendPushNotificationToAllTokens)))

Может ли кто-нибудь объяснить, почему это не работает, и как я могу решить эту проблему, чтобы ограничить скорость только для определенной конечной точки?

Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
API ввода вопросов - это полезный инструмент для интеграции моделей машинного обучения, таких как ChatGPT, в приложения, требующие обработки...
2
0
79
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Различие между использованием простого http.Handler и http.HanlderFunc здесь не имеет большого значения. http.HandleFunc — это просто способ преобразовать обычную функцию в http.Handler — по сути, она делает то же самое, что и исходная версия limit.

Обе ваши реализации limit выглядят нормально; наверное второй лучше, потому что он проще. Вместо этого проблема в main. Когда вы вызываете http.ListenAndServeTLS и указываете значение для последнего аргумента, он запрашивает, чтобы в качестве обработчика корневого запроса использовался только тот обработчик, который вы передаете в качестве этого последнего аргумента. Любые вызовы http.Handle() или http.HandleFunc() игнорируются, если вы не передадите nil в качестве последнего аргумента.

Вместо этого вы хотите применить limit к конкретному обработчику, который вы хотите ограничить. У вас есть два варианта для этого. Во-первых, вы можете использовать ServeMux как в своем первом фрагменте кода:

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", createNewToken)
    // Limit only the handler for "/notify".
    mux.HandleFunc("/notify", limit(sendPushNotificationToAllTokens))

    // Don't limit the whole mux.
    log.Fatal(http.ListenAndServeTLS(":5050", "localhost.crt", "localhost.key", mux))
}

В качестве альтернативы вы можете сделать что-то более похожее на ваш второй фрагмент кода, но передать nil в качестве последнего аргумента http.ListenAndServeTLS, чтобы использовалось http.ServeMux по умолчанию, что означает, что вызовы http.HandleFunc() будут учитываться:

func main() {
    http.HandleFunc("/", createNewToken)
    // Limit only the handler for "/notify".
    http.HandleFunc("/notify", limit(sendPushNotificationToAllTokens))

    // Pass in nil here so that http.DefaultServeMux is used.
    log.Fatal(http.ListenAndServeTLS(":5050", "localhost.crt", "localhost.key", nil))
}

Для простого приложения, вероятно, подойдет первый подход. Для чего-то более сложного я бы рекомендовал более поздний подход, потому что он будет работать, если вы откроете несколько серверов или выполните другие более сложные действия.

Другие вопросы по теме