Forum Programmation.web Service upload de fichiers http

Posté par  . Licence CC By‑SA.
Étiquettes : aucune
1
24
mar.
2020

Bonjour,
je profite de ces temps de confinement pour (re-)pratiquer une activité que j'ai délaissé il y a bien des années : "Geeker" sur mes machines.

J'ai essayé naïvement de faire une petit formulaire http pour téléverser des fichiers sur une de mes machines possedant un server web (nginx)
Mais j'ai des soucis pour la partie backend, une recherche rapide m'a pointé cette page : https://www.nginx.com/resources/wiki/modules/upload/
mais le module à l'air mort depuis quelques années (et n'est plus inclus/compilé avec nginx fourni par ma distribution)

À ma grande surprise, je ne trouve pas d'autre solution simple pour cela.
J'aimerais, autant que possible, continuer à fonctionner avec un serveur web "complet" car j'ai d'autres projets (et pas mal de temps libre, ça tombe bien).
Un autre point important pour moi, est qu'à terme, j'aimerai le rendre disponible en ligne, il devra donc nécessiter une authentification pour être accessible/fonctionnel (mais je suppose, peut-être à tort, que cela est indépendant)

Je précise que je suis absolument débutant en technos et protocoles web.

Quelle est la bonne solution selon vous ?
Merci.

  • # ca depend de ton usage

    Posté par  . Évalué à 3. Dernière modification le 24/03/20 à 14:26.

    si c'est un pour uploader des fichiers sur ton site web, il y a des "FTP via le web"

    si c'est partager des fichiers entre utilisateurs, y a des "cloud" (nextCloud, ownCloud, CozyCloud…)

    • [^] # Re: ca depend de ton usage

      Posté par  . Évalué à 2.

      c'est pour uploader sur la machine qui héberge le site web.

      Sinon je connais les cloud persos oui, mais j'ai envie de m'amuser, d'apprendre et d'essayer de faire des trucs, c'est pour ça que je cherche plutôt à le faire moi même.

  • # Commentaire supprimé

    Posté par  . Évalué à 1. Dernière modification le 24/03/20 à 20:27.

    Ce commentaire a été supprimé par l’équipe de modération.

  • # Commentaire supprimé

    Posté par  . Évalué à 1. Dernière modification le 24/03/20 à 20:46.

    Ce commentaire a été supprimé par l’équipe de modération.

  • # Go

    Posté par  . Évalué à 1.

    En Go, en 1 seul fichier:

    package main
    
    import (
        "fmt"
        "io"
        "log"
        "net/http"
        "os"
        "path/filepath"
    )
    
    func main() {
        createUploadDir(uploadDir)
    
        // on enregistre le handler d'upload sur le / du site dans le routeur par défaut
        http.HandleFunc("/", handleUpload)
        // on écoute sur le port :9090 sur toutes les interfaces de la machine
        // en utilisant le routeur par défaut
        http.ListenAndServe(":9090", nil)
    }
    
    func handleUpload(w http.ResponseWriter, r *http.Request) {
        log.Println("method:", r.Method)
        if r.Method == "GET" {
            // On écrit dans le ResponseWriter le code HTML, ce qui permet d'afficher
            // la page sur le navigateur
            fmt.Fprint(w, uploadHTML)
        } else {
            // Le serveur utilisera 10Mo en mémoire pendant l'upload, le reste
            // sera stocker sur des fichiers temporaire sur le disque.
            r.ParseMultipartForm(10_000_000)
            file, header, err := r.FormFile("uploadfile")
            if err != nil {
                // On logge l'erreur sur le serveur
                log.Println(err)
                // On renvoit une erreur 500 avec le message d'erreur sur le navigateur
                http.Error(w, err.Error(), http.StatusInternalServerError)
                return
            }
            // On ferme le Reader des données de formulaire à la sortie de la fonction
            defer file.Close()
    
            // On ouvre un fichier en écriture pour enregistrer l'upload, dans le dossier d'upload
            f, err := os.OpenFile(filepath.Join(uploadDir, header.Filename), os.O_WRONLY|os.O_CREATE, 0666)
            if err != nil {
                log.Println(err)
                http.Error(w, err.Error(), http.StatusInternalServerError)
                return
            }
            // On ferme le fichier créé à la sortie de la fonction
            defer f.Close()
    
            // On copie les données d'upload dans le fichier sur le serveur
            _, err = io.Copy(f, file)
            if err != nil {
                log.Println(err)
                http.Error(w, err.Error(), http.StatusInternalServerError)
                return
            }
    
            // On écrite les métadonnées du fichier uploadé dans le ResponseWriter
            fmt.Fprint(w, header.Header)
        }
    }
    
    // createUploadDir créé un dossier d'upload où stocker les fichiers
    func createUploadDir(uploadDir string) {
        err := os.Mkdir(uploadDir, 0770)
        if err != nil {
            log.Println(err)
        }
    }
    
    const (
        // uploadDir est le dossier de stockage des fichiers uploadés
        uploadDir = "./test"
    
        // uploadHTML est une chaîne contenant le HTML de la page d'upload
        uploadHTML = `<html>
    <head>
           <title>Upload file</title>
    </head>
    <body>
    <form enctype="multipart/form-data" action="http://127.0.0.1:9090/" method="post">
        <input type="file" name="uploadfile" />
        <input type="submit" value="upload" />
    </form>
    </body>
    </html>`
    )

    Pas le code le plus idiomatique, ni le plus beau, mais il est concis et j'espère "facile" à comprendre. Si besoin d'explications, n'hésite pas.
    Mais clairement, il manque beaucoup pour en faire un truc vraiment correct (jeton CSRF, templating, CSS, etc).
    L'un des avantages, c'est que ça produit un simple fichier binaire que tu peux copier coller sur n'importe quel serveur en ssh, et ça tourne. Pas besoin d'installer 100 packages ou des dépendances dans tous les sens. Juste le binaire et c'est bon.

    C'est inspiré de https://astaxie.gitbooks.io/build-web-application-with-golang/en/04.5.html

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n’en sommes pas responsables.