使用 io.Pipe 从 exec.command 获取输出以进行 http post
Posted
技术标签:
【中文标题】使用 io.Pipe 从 exec.command 获取输出以进行 http post【英文标题】:Using io.Pipe to get output from exec.command to make http post 【发布时间】:2021-11-29 09:18:15 【问题描述】:正在阅读使用 io.Pipe 来减少分配(无需将 cmd.Stdout
分配给 bytes.Buffer)。如果我非常了解如何使用 io.Pipe 从 exec.command 获取输出以发出 http mutliform 发布请求,我无法让以下工作和感激。
func main()
cmd := exec.Command("convert", "test.png", "-resize" "30x30", "png:-")
bodyReader, bodyWriter := io.Pipe()
cmd.Stdout = bodyWriter
formWriter := multipart.NewWriter(bodyWriter)
go func()
cmd.Run()
partWriter, err := formWriter.CreateFormFile("file", "file")
if err != nil
fmt.Println("form writer create error")
return
_, err = io.Copy(partWriter, bodyReader)
if err != nil
fmt.Println("io copy error")
return
formWriter.Close()
bodyWriter.Close()
()
url := "http://example.com/upload"
req, _ := http.NewRequest(http.MethodPost, url, bodyReader)
req.Header.Set("Content-Type", formWriter.FormDataContentType())
resp, err := http.DefaultClient.Do(req)
if err != nil
fmt.Println("htttp do error")
return
fmt.Println(resp.StatusCode)
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil
fmt.Println("read error")
return
fmt.Println("Result:", string(respBody))
使用调试工具,它只是挂在resp, err := http.DefaultClient.Do(req)
,最终输出如下。
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x10 pc=0x1218c3b]
goroutine 1 [running]:
main.main()
【问题讨论】:
程序中哪一行代码出现了恐慌? 【参考方案1】:通过将命令的标准输出设置为部分编写器来修复。
func main()
bodyReader, bodyWriter := io.Pipe()
formWriter := multipart.NewWriter(bodyWriter)
go func() (err error)
defer func()
bodyWriter.CloseWithError(err)
()
partWriter, err := formWriter.CreateFormFile("file", "file")
if err != nil
return err
cmd := exec.Command("convert", "test.png", "-resize" "30x30", "png:-")
cmd.Stdout = partWriter
if err := cmd.Run(); err != nil
return err
formWriter.Close()
return nil
()
...
Run an example on the playground.
额外改进:使用 CloseWithError 将错误从 goroutine 传播到主函数。
【讨论】:
【参考方案2】:您需要为multipart.Writer
添加另一个Pipe
func main()
cmd := exec.Command("convert", "./test.jpg", "-resize", "30x30", "jpg:-")
bodyReader, bodyWriter := io.Pipe()
cmd.Stdout = bodyWriter
cmd.Stderr = os.Stderr
formReader, formWriter := io.Pipe()
multiWriter := multipart.NewWriter(formWriter)
go func()
if err := cmd.Run(); err != nil
bodyWriter.CloseWithError(err)
else
bodyWriter.Close()
()
go func()
partWriter, err := multiWriter.CreateFormFile("file", "file")
if err != nil
formWriter.CloseWithError(err)
return
_, err = io.Copy(partWriter, bodyReader)
if err != nil
formWriter.CloseWithError(err)
return
multiWriter.Close()
formWriter.Close()
()
url := "http://example.com/upload"
req, _ := http.NewRequest(http.MethodPost, url, formReader)
fmt.Println(multiWriter.FormDataContentType())
req.Header.Set("Content-Type", multiWriter.FormDataContentType())
resp, err := http.DefaultClient.Do(req)
if err != nil
fmt.Println("htttp do error")
return
fmt.Println(resp.StatusCode)
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil
fmt.Println("read error")
return
fmt.Println("Result:", string(respBody))
【讨论】:
工作...谢谢... 请提出另一个后续问题。如果 linesize, err = io.Copy(partWriter, bodyReader)
已创建,我如何在 main 函数中获取大小?
你可以关注这个帖子***.com/questions/20945069/…以上是关于使用 io.Pipe 从 exec.command 获取输出以进行 http post的主要内容,如果未能解决你的问题,请参考以下文章
exec.Command错误,没有输出到stdout或stderr
防止 Ctrl+C 中断 Golang 中的 exec.Command
在 Golang 中运行 exec.Command 时如何调试“退出状态 1”错误