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)
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 网站后台使用极速模式非常的卡
  • ¥20 Keil uVision5创建project没反应
  • ¥15 mmseqs内存报错
  • ¥15 vika文档如何与obsidian同步
  • ¥15 华为手机相册里面的照片能够替换成自己想要的照片吗?
  • ¥15 陆空双模式无人机飞控设置
  • ¥15 sentaurus lithography
  • ¥100 求抖音ck号 或者提ck教程
  • ¥15 关于#linux#的问题:子进程1等待子进程A、B退出后退出(语言-c语言)
  • ¥20 web页面如何打开Outlook 365的全球离线通讯簿功能