美文网首页
iris实现单文件/多文件上传自定义文件名

iris实现单文件/多文件上传自定义文件名

作者: 我爱张智容 | 来源:发表于2021-02-10 12:11 被阅读0次

上代码:

package main

import (
    "crypto/md5"
    "fmt"
    "io"
    "os"
    "path"
    "strconv"
    "time"

    "github.com/kataras/iris/v12"
)

const maxSize = 5 << 20 // 5MB

func main() {
    app := iris.New()

    app.RegisterView(iris.HTML("./templates", ".html"))

    // Serve the upload_form.html to the client.
    app.Get("/upload", func(ctx iris.Context) {
        // create a token (optionally).

        now := time.Now().Unix()
        h := md5.New()
        io.WriteString(h, strconv.FormatInt(now, 10))
        token := fmt.Sprintf("%x", h.Sum(nil))

        // render the form with the token for any use you'd like.
        // ctx.ViewData("", token)
        // or add second argument to the `View` method.
        // Token will be passed as {{.}} in the template.
        ctx.View("upload_form.html", token)
    })

    /* Read before continue.

    0. The default post max size is 32MB,
    you can extend it to read more data using the `iris.WithPostMaxMemory(maxSize)` configurator at `app.Run`,
    note that this will not be enough for your needs, read below.

    1. The faster way to check the size is using the `ctx.GetContentLength()` which returns the whole request's size
    (plus a logical number like 2MB or even 10MB for the rest of the size like headers). You can create a
    middleware to adapt this to any necessary handler.

    myLimiter := func(ctx iris.Context) {
        if ctx.GetContentLength() > maxSize { // + 2 << 20 {
            ctx.StatusCode(iris.StatusRequestEntityTooLarge)
            return
        }
        ctx.Next()
    }

    app.Post("/upload", myLimiter, myUploadHandler)

    Most clients will set the "Content-Length" header (like browsers) but it's always better to make sure that any client
    can't send data that your server can't or doesn't want to handle. This can be happen using
    the `app.Use(LimitRequestBodySize(maxSize))` (as app or route middleware)
    or the `ctx.SetMaxRequestBodySize(maxSize)` to limit the request based on a customized logic inside a particular handler, they're the same,
    read below.

    2. You can force-limit the request body size inside a handler using the `ctx.SetMaxRequestBodySize(maxSize)`,
    this will force the connection to close if the incoming data are larger (most clients will receive it as "connection reset"),
    use that to make sure that the client will not send data that your server can't or doesn't want to accept, as a fallback.

    app.Post("/upload", iris.LimitRequestBodySize(maxSize), myUploadHandler)

    OR

    app.Post("/upload", func(ctx iris.Context){
        ctx.SetMaxRequestBodySize(maxSize)

        // [...]
    })

    3. Another way is to receive the data and check the second return value's `Size` value of the `ctx.FormFile`, i.e `info.Size`, this will give you
    the exact file size, not the whole incoming request data length.

    app.Post("/", func(ctx iris.Context){
        file, info, err := ctx.FormFile("uploadfile")
        if err != nil {
            ctx.StatusCode(iris.StatusInternalServerError)
            ctx.HTML("Error while uploading: <b>" + err.Error() + "</b>")
            return
        }

        defer file.Close()

        if info.Size > maxSize {
            ctx.StatusCode(iris.StatusRequestEntityTooLarge)
            return
        }

        // [...]
    })
    */

    // Handle the post request from the upload_form.html to the server
    app.Post("/upload", iris.LimitRequestBodySize(maxSize+1<<20), func(ctx iris.Context) {
        // Get the file from the request.
        file, info, err := ctx.FormFile("uploadfile")
        if err != nil {
            ctx.StatusCode(iris.StatusInternalServerError)
            ctx.HTML("Error while uploading: <b>" + err.Error() + "</b>")
            return
        }

        defer file.Close()

       //时间戳纳秒实现的自定义文件名
        newFilename := strconv.Itoa(int(time.Now().UnixNano())) + path.Ext(info.Filename)

        // Create a file with the same name
        // assuming that you have a folder named 'uploads'
        out, err := os.OpenFile("./uploads/"+newFilename, os.O_WRONLY|os.O_CREATE, 0666)
        if err != nil {
            ctx.StatusCode(iris.StatusInternalServerError)
            ctx.HTML("Error while uploading: <b>" + err.Error() + "</b>")
            return
        }
        defer out.Close()

        io.Copy(out, file)
    })

    // start the server at http://localhost:8080 with post limit at 5 MB.
    app.Run(iris.Addr(":8080") /* 0.*/, iris.WithPostMaxMemory(maxSize))
}

多文件上传 :

package main

import (
    "crypto/md5"
    "fmt"
    "io"
    "mime/multipart"
    "os"
    "path/filepath"
    "strconv"
    "strings"
    "time"

    "github.com/kataras/iris/v12"
)

func main() {
    app := iris.New()

    app.RegisterView(iris.HTML("./templates", ".html"))

    // Serve the upload_form.html to the client.
    app.Get("/upload", func(ctx iris.Context) {
        // create a token (optionally).

        now := time.Now().Unix()
        h := md5.New()
        io.WriteString(h, strconv.FormatInt(now, 10))
        token := fmt.Sprintf("%x", h.Sum(nil))

        // render the form with the token for any use you'd like.
        ctx.View("upload_form.html", token)
    })

    // Handle the post request from the upload_form.html to the server.
    app.Post("/upload", func(ctx iris.Context) {
        //
        // UploadFormFiles
        // uploads any number of incoming files ("multiple" property on the form input).
        //

        // second argument is totally optionally,
        // it can be used to change a file's name based on the request,
        // at this example we will showcase how to use it
        // by prefixing the uploaded file with the current user's ip.
        ctx.UploadFormFiles("./uploads", beforeSave)
    })

    app.Post("/upload_manual", func(ctx iris.Context) {
        // Get the max post value size passed via iris.WithPostMaxMemory.
        maxSize := ctx.Application().ConfigurationReadOnly().GetPostMaxMemory()

        err := ctx.Request().ParseMultipartForm(maxSize)
        if err != nil {
            ctx.StatusCode(iris.StatusInternalServerError)
            ctx.WriteString(err.Error())
            return
        }

        form := ctx.Request().MultipartForm

        files := form.File["files[]"]
        failures := 0
        for _, file := range files {
            _, err = saveUploadedFile(file, "./uploads")
            if err != nil {
                failures++
                ctx.Writef("failed to upload: %s\n", file.Filename)
            }
        }
        ctx.Writef("%d files uploaded", len(files)-failures)
    })

    // start the server at http://localhost:8080 with post limit at 32 MB.
    app.Run(iris.Addr(":8080"), iris.WithPostMaxMemory(32<<20))
}

func saveUploadedFile(fh *multipart.FileHeader, destDirectory string) (int64, error) {
    src, err := fh.Open()
    if err != nil {
        return 0, err
    }
    defer src.Close()

    out, err := os.OpenFile(filepath.Join(destDirectory, fh.Filename),
        os.O_WRONLY|os.O_CREATE, os.FileMode(0666))
    if err != nil {
        return 0, err
    }
    defer out.Close()

    return io.Copy(out, src)
}

func beforeSave(ctx iris.Context, file *multipart.FileHeader) {
    ip := ctx.RemoteAddr()
    // make sure you format the ip in a way
    // that can be used for a file name (simple case):
    ip = strings.Replace(ip, ".", "_", -1)
    ip = strings.Replace(ip, ":", "_", -1)

    // you can use the time.Now, to prefix or suffix the files
    // based on the current time as well, as an exercise.
    // i.e unixTime :=  time.Now().Unix()
    // prefix the Filename with the $IP-
    // no need for more actions, internal uploader will use this
    // name to save the file into the "./uploads" folder.
    file.Filename = ip + "-" + file.Filename
}

相关文章

网友评论

      本文标题:iris实现单文件/多文件上传自定义文件名

      本文链接:https://www.haomeiwen.com/subject/rysptltx.html