Как определить, достиг ли я предела размера через Go's MaxBytesReader

Я новичок в Go и использую Mux для приема данных HTTP POST. Я хотел бы использовать MaxBytesReader, чтобы клиент не перегружал мой сервер. Согласно кодексу, есть requestBodyLimit логическое значение, которое указывает, был ли достигнут этот предел.

Мой вопрос: при использовании MaxBytesReader, как я могу определить, действительно ли я достиг максимума при обработке запроса?

Вот мой код:

package main

import (
        "fmt"
        "log"
        "html/template"
        "net/http"

        "github.com/gorilla/mux"
)

func main() {
        r := mux.NewRouter()
        r.HandleFunc("/handle", maxBytes(PostHandler)).Methods("POST")
        http.ListenAndServe(":8080", r)
}

// Middleware to enforce the maximum post body size
func maxBytes(f http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
            // As an example, limit post body to 10 bytes
            r.Body = http.MaxBytesReader(w, r.Body, 10)
            f(w, r)
    }
}

func PostHandler(w http.ResponseWriter, r *http.Request) {
    // How do I know if the form data has been truncated?
    book := r.FormValue("email")
    fmt.Fprintf(w, "You've requested the book: %s\n", book)
}

Как я могу:

  • Определите, что я достиг максимального предела POST (или имею доступ к requestBodyLimit

  • Может ли мой код быть разветвленным при этом условии?

3 ответа

Решение

Вызовите ParseForm в начале обработчика. Если этот метод возвращает ошибку, то предел размера был нарушен или тело запроса каким-то образом недопустимо. Напишите статус ошибки и вернитесь из обработчика.

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

func PostHandler(w http.ResponseWriter, r *http.Request) {
    if err := r.ParseForm(); err != nil {
        http.Error(w, "Bad Request", http.StatusBadRequest)
        return
    }

    book := r.FormValue("email")
    fmt.Fprintf(w, "You've requested the book: %s\n", book)
}

В зависимости от ваших потребностей, может быть лучше поместить чек в промежуточное ПО:

func maxBytes(f http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
            r.Body = http.MaxBytesReader(w, r.Body, 10)
            if err := r.ParseForm(); err != nil {
                http.Error(w, "Bad Request", http.StatusBadRequest)
                return
            }
            f(w, r)
    }
}

Можно проверить, является ли возвращенная ошибкаhttp.MaxBytesErrorтак:

      r.Body = http.MaxBytesReader(w, r.Body, 10)
if err := r.ParseForm(); err != nil {
    if _, ok := err.(*http.MaxBytesError); ok {
        // handle http.StatusRequestEntityTooLarge error
    }
      // handle http.StatusBadRequest error
}

errors.Is()иerrors.As()в этом случае работать не будет.

Вы можете определить, был ли предел превышен, проверяя, превышает ли длина прочитанных данных (или равна) MaxBytesSize:

maxBytesSize := 10
r.Body = http.MaxBytesReader(w, r.Body, maxBytesSize)

// check if request body is not too large
data, err := ioutil.ReadAll(r.Body)
if err != nil {
    if len(data) >= maxBytesSize {
         //exceeded
    }
    // some other error
}
Другие вопросы по тегам