douerlin4366 2018-12-11 07:25
浏览 528
已采纳

http PUT请求以golang上传zip文件

I have client code which is basically trying to upload a tar.gz file to the server using a HTTP PUT METHOD. However the server seems to not like it and always seems to send me a 500 ERROR Response. Following is the code. I am not sure what is going wrong.

 func upLoadFileToServer (uploadFileName string) {
    tr := &http.Transport{
          TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
          ExpectContinueTimeout : 30 * time.Second,
        }

    client := &http.Client{ Transport:tr,
                          Timeout: 20 * time.Second}

    timeCurrent = time.Now()
    fileContents, err := ioutil.ReadFile(uploadFileName)
    if err != nil {
     log.Println("Failed to Read the File", uploadFileName, err)
    }

    PutReq, _ := http.NewRequest("PUT", "https://www.example.com/upload", strings.NewReader(string(fileContents)))

    PutReq.Header.Set("Content-Type", "application/zip")
    PutReq.ContentLength = int64(len(string(fileContents)))


    PutReq.Header.Set("Expect", "100-continue")
    PutReq.Header.Set("Accept", "*/*")
    PutReq.Header.Set("Date", timeCurrent.Format(time.RFC1123))
    PutResp, err := client.Do(inventoryPutReq)
    }

Sometimes I notice Connection RESET by PEER error. But most of the times it is 500. I try the exact same request using POSTMAN and it seems to work fine.

  • 写回答

1条回答 默认 最新

  • duanguai2781 2018-12-11 10:20
    关注

    This is a working example.

    Most likely, it comes down to the fact that the server is a bit simple and takes the filename literally. And since you are not using filepath.Base on your uploadFileName, it might have path elements on it. Simply use it on your filename for testing purposes.

    The resets might be caused by the timeouts.

    package main
    
    import (
        "bytes"
        "flag"
        "fmt"
        "io"
        "log"
        "mime/multipart"
        "net"
        "net/http"
        "os"
        "path/filepath"
        "sync"
    )
    
    var (
        targetPath string
        filename   string
        port       int
        handlerLog *log.Logger
        mainLog    *log.Logger
    )
    
    // This is automatically called after vars have been initialized and before main
    func init() {
        flag.StringVar(&targetPath, "target", "./tmp", "target directory for uploads")
        flag.StringVar(&filename, "file", "", "file to upload")
        flag.IntVar(&port, "port", 0, "port to listen on. When 0, a random port is assigned")
        handlerLog = log.New(os.Stdout, "[handler] ", log.LstdFlags)
        mainLog = log.New(os.Stdout, "[main   ] ", log.LstdFlags)
    }
    
    // By returning a handler, we have an elegant way of initializing path.
    func uploadHandler(path string) http.Handler {
    
        // We make sure path is an existing directory when the handler takes over
        if s, err := os.Stat(path); err != nil {
            if os.IsNotExist(err) {
                handlerLog.Printf("Target '%s' does not exist. Creating it...", path)
                if cerr := os.MkdirAll(path, 0755); cerr != nil {
                    handlerLog.Fatalf("Creating target: %s", err)
                }
            } else {
                handlerLog.Fatalf("Error accessing '%s': %s", path, err)
            }
        } else if !s.IsDir() {
            handlerLog.Fatalf("Target '%s' is not a directory", path)
        }
    
        // Do NOT use this handler in production!!!
        // It is lacking all sorts of safety measures.
        // However, it is enough to demonstrate.
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            handlerLog.Println("Handling file upload...")
    
            handlerLog.Println("Parsing form...")
            if err := r.ParseMultipartForm(32 << 20); err != nil {
                handlerLog.Fatalf("Parsing form: %s", err)
            }
            f, h, err := r.FormFile("file")
            if err != nil {
                handlerLog.Printf("Error accessing file: %s", err)
                http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
                return
            }
            defer f.Close()
    
            handlerLog.Println("Opening output file...")
            t, err := os.OpenFile(filepath.Join(path, filepath.Base(h.Filename)), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
            if err != nil {
                handlerLog.Printf("Opening output file: %s", err)
                http.Error(w, http.StatusText(http.StatusInternalServerError)+": "+err.Error(), http.StatusInternalServerError)
                return
            }
            defer t.Close()
    
            handlerLog.Println("Copying to output file...")
            if _, err = io.Copy(t, f); err != nil {
                handlerLog.Printf("Copying to output file: %s", err)
    
                http.Error(w, http.StatusText(http.StatusInternalServerError)+": "+err.Error(), http.StatusInternalServerError)
                return
            }
            handlerLog.Println("Finished handler!")
        })
    }
    
    func main() {
        flag.Parse()
    
        // Check input
        if filename == "" {
            mainLog.Fatal("No filename given. Exiting...")
        }
    
        mainLog.Println("Setting up upload handler...")
        http.Handle("/upload", uploadHandler(targetPath))
    
        wg := sync.WaitGroup{}
        wg.Add(1)
    
        // We want to finish the program after upload, as we only want to demonstrate
        go func() {
            mainLog.Println("Setting up listener...")
    
            listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port))
            if err != nil {
                mainLog.Fatalf("%s", err)
            }
            defer listener.Close()
    
            port = listener.Addr().(*net.TCPAddr).Port
            mainLog.Printf("Listening to port %d on localhost", port)
    
            wg.Done()
            http.Serve(listener, nil)
        }()
    
        buf := bytes.NewBuffer(nil)
        bodyWriter := multipart.NewWriter(buf)
    
        // We need to truncate the input filename, as the server might be stupid and take the input
        // filename verbatim. Then, he will have directory parts which do not exist on the server.
        fileWriter, err := bodyWriter.CreateFormFile("file", filepath.Base(filename))
        if err != nil {
            mainLog.Fatalf("Creating fileWriter: %s", err)
        }
    
        file, err := os.Open(filename)
        if err != nil {
            mainLog.Fatalf("Opening file: %s", err)
        }
        defer file.Close()
    
        if _, err := io.Copy(fileWriter, file); err != nil {
            mainLog.Fatalf("Buffering file: %s", err)
        }
    
        // We have all the data written to the bodyWriter.
        // Now we can infer the content type
        contentType := bodyWriter.FormDataContentType()
    
        // This is mandatory as it flushes the buffer.
        bodyWriter.Close()
    
        // As we wait for the server to spin up, we need to wait here.
        mainLog.Println("Waiting for the listener to be set up...")
        wg.Wait()
    
        req, err := http.NewRequest(http.MethodPut, fmt.Sprintf("http://127.0.0.1:%d/upload", port), buf)
        if err != nil {
            mainLog.Fatalf("Creating request: %s", err)
        }
        req.Header.Set("Content-Type", contentType)
    
        client := http.Client{}
    
        mainLog.Println("Sending file")
        res, err := client.Do(req)
        if err != nil {
            mainLog.Fatalf("Sending file: %s", err)
        }
    
        mainLog.Printf("Received %s from server. Exiting...", res.Status)
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 深度学习根据CNN网络模型,搭建BP模型并训练MNIST数据集
  • ¥15 lammps拉伸应力应变曲线分析
  • ¥15 C++ 头文件/宏冲突问题解决
  • ¥15 用comsol模拟大气湍流通过底部加热(温度不同)的腔体
  • ¥50 安卓adb backup备份子用户应用数据失败
  • ¥20 有人能用聚类分析帮我分析一下文本内容嘛
  • ¥15 请问Lammps做复合材料拉伸模拟,应力应变曲线问题
  • ¥30 python代码,帮调试,帮帮忙吧
  • ¥15 #MATLAB仿真#车辆换道路径规划
  • ¥15 java 操作 elasticsearch 8.1 实现 索引的重建