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

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)
    }
    
    已采纳该答案
    评论
    解决 无用
    打赏 举报

相关推荐 更多相似问题