De ce nu încărcarea de fișiere ~2,5 MiB sau mai mari provoca o conexiune de resetare?

0

Problema

Suntem încearcă să pună în aplicare de imagine încărcarea prin POSTA cereri. Dorim, de asemenea, pentru a limita imagini de la ~1,0 MiB. Aceasta funcționează bine în imagini mai mici, dar nimic ~2,5 MiB sau mai mari cauze de conexiune pentru a reseta. De asemenea, pare a trimite mai multe cereri după primul la aceeași handler.

principal.du-te:

package main

import (
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/", uploadHandler)
    http.ListenAndServe("localhost:8080", nil)
}

func uploadHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method == "POST" {
        postHandler(w, r)
        return
    } else {
        http.ServeFile(w, r, "index.html")
    }
}

func postHandler(w http.ResponseWriter, r *http.Request) {
    // Send an error if the request is larger than 1 MiB
    if r.ContentLength > 1<<20 {
        // if larger than ~2,5 MiB, this will print 2 or more times
        log.Println("File too large")
        // And this error will never arrive, instead a Connection reset
        http.Error(w, "response too large", http.StatusRequestEntityTooLarge)
        return
    }
    return
}

index.html:

<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <form method="POST" enctype="multipart/form-data">
      <input type="file" accept="image/*" name="profile-picture"><br>
      <button type="submit" >Upload</button>
  </form>
  </body>
</html>

Ieșire atunci când încărcarea o ~2,4 fișier MiB

$ go run main.go
2021/11/23 22:00:14 File too large

Ea arată, de asemenea, "cererea este prea mare" în browser-ul

Ieșire atunci când încărcarea ~2,5 fișier MiB

$ go run main.go
2021/11/23 22:03:25 File too large
2021/11/23 22:03:25 File too large

Browser-ul arată acum că conexiunea a fost reinițializată

go http
2021-11-23 20:06:27
1

Cel mai bun răspuns

3

Clientul este încercarea de a trimite datele la server. Serverul nu este citirea datelor, se uită doar la cap și închide conexiunea. Clientul este de a interpreta acest lucru ca "conexiunea a fost resetata". Acest lucru este în afara controlului tău.

În loc de a verifica antet, antet poate minți, utilizare http.MaxBytesReader pentru a citi conținutul real, dar de eroare dacă este prea mare.

const MAX_UPLOAD_SIZE = 1<<20

func postHandler(w http.ResponseWriter, r *http.Request) {
    // Wrap the body in a reader that will error at MAX_UPLOAD_SIZE
    r.Body = http.MaxBytesReader(w, r.Body, MAX_UPLOAD_SIZE)

    // Read the body as normal. Check for an error.
    if err := r.ParseMultipartForm(MAX_UPLOAD_SIZE); err != nil {
        // We're assuming it errored because the body is too large.
        // There are other reasons it could error, you'll have to
        // look at err to figure that out.
        log.Println("File too large")
        http.Error(w, "Your file is too powerful", http.StatusRequestEntityTooLarge)
        return
    }

    fmt.Fprintf(w, "Upload successful")
}

A se vedea Cum pentru procesul de încărcări de fișiere, în Du-te pentru mai multe detalii.

2021-11-23 20:55:11

Acest lucru pare să funcționeze pentru a o extinde și de fapt se potriveste nevoilor noastre. Cu toate acestea, el încă mai provoacă o conexiune reset cu un suficient de mare de imagine ca asta, deci de exemplu, dacă am vrut pentru a ridica MAX_UPLOAD_SIZE să 20 << 20 pentru orice motiv, nu ar fi capabil de a încărca ceva de dimensiunea asta.
urist

De asemenea, am crezut că r.ContentLength ar putea fi folosit ca o verificare rapidă înainte de orice fișiere sunt chiar încărcate la toate, chiar dacă știu că ar putea fi falsificata. Cred ca ai putea pune în aplicare acest lucru în partea de client de lucruri
urist

Cred că mi-am dat seama de ce conexiunea a fost resetată din comentariu de mai sus, aveți nevoie pentru a începe de fapt, folosind date (de exemplu cu r.FormFile), în caz contrar se va opri și să se întoarcă, și închide conexiunea odată ce începe obtinerea deranjat de date constantă de a fi trimis către client.
urist

În alte limbi

Această pagină este în alte limbi

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................