Go:跟踪POST请求的进度

huangapple go评论76阅读模式
英文:

Go: Tracking POST request progress

问题

我正在使用Go语言编写一个在Linux上的ShareX克隆版本,通过HTTP POST请求将文件和图片上传到文件共享服务。

目前我正在使用http.Client和Do()方法发送请求,但是我希望能够跟踪上传进度,特别是对于需要花费一分钟上传的大文件。
目前我能想到的唯一方法是手动打开一个TCP连接到网站的80端口,并以块的方式编写HTTP请求,但我不知道它是否适用于HTTPS网站,也不确定这是否是最佳方法。

是否有其他方法可以实现这个功能呢?

英文:

I'm coding a ShareX clone for Linux in Go that uploads files and images to file sharing services through http POST requests.

I'm currently using http.Client and Do() to send my requests, but I'd like to be able to track the upload progress for bigger files that take up to a minute to upload.
The only way I can think of at the moment is manually opening a TCP connection on port 80 to the website and write the HTTP request in chunks, but I don't know if it would work on https sites and I'm not sure if it's the best way to do it.

Is there any other way to achieve this?

答案1

得分: 22

你可以创建自己的io.Reader来包装实际的读取器,然后每次调用Read时输出进度。

可以按照以下方式进行操作:

type ProgressReader struct {
    io.Reader
    Reporter func(r int64)
}

func (pr *ProgressReader) Read(p []byte) (n int, err error) {
    n, err = pr.Reader.Read(p)
    pr.Reporter(int64(n))
    return
}

func main() {
    file, _ := os.Open("/tmp/blah.go")
    total := int64(0)
    pr := &ProgressReader{file, func(r int64) {
        total += r
        if r > 0 {
            fmt.Println("progress", r)
        } else {
            fmt.Println("done", r)
        }
    }}
    io.Copy(ioutil.Discard, pr)
}
英文:

You can create your own io.Reader to wrap the actual reader and then you can output the progress each time Read is called.

Something along the lines of:

type ProgressReader struct {
	io.Reader
	Reporter func(r int64)
}

func (pr *ProgressReader) Read(p []byte) (n int, err error) {
	n, err = pr.Reader.Read(p)
	pr.Reporter(int64(n))
	return
}

func main() {
	file, _ := os.Open("/tmp/blah.go")
	total := int64(0)
	pr := &ProgressReader{file, func(r int64) {
		total += r
		if r > 0 {
			fmt.Println("progress", r)
		} else {
			fmt.Println("done", r)
		}
	}}
	io.Copy(ioutil.Discard, pr)
}

答案2

得分: 10

将作为请求体传递的读取器包装在能够报告进度的结构中。例如,

type progressReporter struct {
     r io.Reader
     max int
     sent int
}

func (pr *progressReader) Read(p []byte) (int, error) {
     n, err := pr.r.Read(p)
     pr.sent += n
     if err == io.EOF {
         pr.atEOF = true
     }
     pr.report()
     return n, err
}

func (pr *progressReporter) report() {
   fmt.Printf("已发送 %d 字节,共 %d 字节\n", pr.sent, pr.max)
   if pr.atEOF {
     fmt.Println("完成")
   }
}

如果之前你调用了

client.Post(u, contentType, r)

那么将代码更改为

client.Post(u, contentType, &progressReader{r:r, max:max})

其中 max 是你预计发送的字节数。根据你的具体需求修改 progressReporter.report() 方法并向 progressReporter 添加字段。

英文:

Wrap the reader passed as the request body with something that reports progress. For example,

type progressReporter struct {
     r io.Reader
     max int
     sent int
}

func (pr *progressReader) Read(p []byte) (int, error) {
     n, err := pr.r.Read(p)
     pr.sent += n
     if err == io.EOF {
         pr.atEOF = true
     }
     pr.report()
     return n, err
}

func (pr *progressReporter) report() {
   fmt.Printf("sent %d of %d bytes\n", pr.sent, pr.max)
   if pr.atEOF {
     fmt.Println("DONE")
   }
}

If previously you called

client.Post(u, contentType, r)

then change the code to

client.Post(u, contentType, &progressReader{r:r, max:max})

where max is the number of bytes you expect to send. Modify the progressReporter.report() method and add fields to progressReporter to meet your specific needs.

huangapple
  • 本文由 发表于 2014年9月26日 08:49:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/26050380.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定