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

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 乌班图ip地址配置及远程SSH
  • ¥15 怎么让点阵屏显示静态爱心,用keiluVision5写出让点阵屏显示静态爱心的代码,越快越好
  • ¥15 PSPICE制作一个加法器
  • ¥15 javaweb项目无法正常跳转
  • ¥15 VMBox虚拟机无法访问
  • ¥15 skd显示找不到头文件
  • ¥15 机器视觉中图片中长度与真实长度的关系
  • ¥15 fastreport table 怎么只让每页的最下面和最顶部有横线
  • ¥15 java 的protected权限 ,问题在注释里
  • ¥15 这个是哪里有问题啊?