duanlei1957 2017-11-21 14:00
浏览 144
已采纳

用于文件上传但不使用ParseMultipartForm的GO REST端点

Newbie here. I'm trying to build a web server with a RESTful API so that I can test a curl command for file uploads. I was able to create the web server and an endpoint for file uploads.

Here is my upload endpoint:

func Upload(w http.ResponseWriter, r *http.Request) {
    if err := r.ParseMultipartForm(MAX_MEMORY); err != nil {
        log.Println(err)
        http.Error(w, err.Error(), http.StatusForbidden)
    }

    fmt.Println("Endpoint hit: Upload")

    for key, value := range r.MultipartForm.Value {
        fmt.Fprintf(w, "%s:%s ", key, value)
        log.Printf("%s:%s", key, value)
    }

    for _, fileHeaders := range r.MultipartForm.File {
        for _, fileHeader := range fileHeaders {
            file, _ := fileHeader.Open()
            path := fmt.Sprintf("files/%s", fileHeader.Filename)
            buf, _ := ioutil.ReadAll(file)
            ioutil.WriteFile(path, buf, os.ModePerm)
            log.Println(http.StatusOK, fmt.Sprintf("file %s has been uploaded", fileHeader.Filename))
        }
    }
}

This endpoint works with the following curl command:

curl -F 'data=@/path/to/file/foo.tar.gz' localhost:8080/upload

However, this curl command does not:

curl -f -s -S -T /path/to/file/foo.tar.gz http://localhost:8080/upload
curl: (22) The requested URL returned error: 405 Method Not Allowed

I need help creating an endpoint that will accept

curl -f -s -S -T /path/to/file/foo.tar.gz http://localhost:8080/upload

Thank you.

Edit: Here is my routes.go file.

package main

import (
    "net/http"
    "github.com/gorilla/mux"
)

type Route struct {
    Name        string
    Method      string
    Pattern     string
    HandlerFunc http.HandlerFunc
}

type Routes []Route

func NewRouter() *mux.Router {
    router := mux.NewRouter().StrictSlash(true)
    for _, route := range routes {
        router.
        Methods(route.Method).
        Path(route.Pattern).
        Name(route.Name).
        Handler(route.HandlerFunc)
    }

    return router
}


var routes = Routes{
    Route{
        "Index",
        "GET",
        "/",
        Index,
    },
    Route{
        "Upload",
        "POST",
        "/upload",
        Upload,
    },
}
  • 写回答

1条回答 默认 最新

  • dq1230123 2017-11-21 15:29
    关注

    Using curl -f -s -S -T /path/to/file/foo.tar.gz http://localhost:8080/upload without any additional options that would set the content type, if there are such options (i'm not sure, my curl knowledge is almost non existent), you are sending a request with minimal headers, none of them indicating the type of the content.

    For example logging the r.Header will print something like this:

    map[Accept:[*/*] Content-Length:[18] Expect:[100-continue] User-Agent:[curl/7.54.0]]
    

    This means that all that multipart code in your Upload handler is simply not necessary.


    The content of the body is what you want, so you can use io.Copy to store that body into a file.

    func Upload(w http.ResponseWriter, r *http.Request) {
        f, err := os.Create("filename")
        if err != nil {
            panic(err)
        }
        defer f.Close()
    
        if _, err := io.Copy(f, r.Body); err != nil {
            panic(err)
        }
        if err := f.Sync(); err != nil {
            panic(err)
        }
        fmt.Fprintln(w, "upload done...")
    }
    

    Since you're using curl -f -s -S -T ... the Upload handler does not know what the name, nor the type, of the file being uploaded is, you will have to generate a random name, or a timestamp name, or whatever in order to be able to create and store more than just one file.

    You could also pass some of the file info (name, type) in the query parameters but i'm not sure if that satisfies your requirements. E.g.

    curl -f -s -S -T /path/to/file/foo.tar.gz http://localhost:8080/upload?name=foo.tar.gz
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥200 关于#c++#的问题,请各位专家解答!
  • ¥50 导入文件到网吧的电脑并且在重启之后不会被恢复
  • ¥15 (希望可以解决问题)ma和mb文件无法正常打开,打开后是空白,但是有正常内存占用,但可以在打开Maya应用程序后打开场景ma和mb格式。
  • ¥15 绘制多分类任务的roc曲线时只画出了一类的roc,其它的auc显示为nan
  • ¥20 ML307A在使用AT命令连接EMQX平台的MQTT时被拒绝
  • ¥20 腾讯企业邮箱邮件可以恢复么
  • ¥15 有人知道怎么将自己的迁移策略布到edgecloudsim上使用吗?
  • ¥15 错误 LNK2001 无法解析的外部符号
  • ¥50 安装pyaudiokits失败
  • ¥15 计组这些题应该咋做呀