使用Docker的Go SDK时输出中出现了杂散字符。

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

Stray characters in output when using Docker's Go SDK

问题

我正在尝试将通过Go的docker-sdk运行Docker镜像后获得的io.ReadCloser(接口)转换为[]byte以供进一步使用。

当我使用stdcopy.StdCopyio.ReadCloser读取到stdout时,它可以完美地打印数据。

以下代码stdcopy.StdCopy(os.Stderr, os.Stdout, out)打印的内容如下:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-html -->

Content-Type: text/html

<html>
<head><title>HTML response</title></head>
<body><h1>Hello, Goodbye</h1></body>
</html>

<!-- end snippet -->

因为我需要将整个内容作为响应发送,所以我需要将内容转换为[]bytestring。但是,一旦我将io.ReadCloser转换为[]bytestring,使用除了stdcopy.StdCopy之外的任何方法,它会在某些行添加特殊字符。

我使用以下代码从out读取到buf,使用*bytes.Buffer.ReadFrom

    buf := new(bytes.Buffer)
	buf.ReadFrom(out)
	fmt.Println(buf.String())

打印的结果如下:
<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-html -->

Content-Type: text/html

<html>
*<head><title>HTML response</title></head>
%<body><h1>Hello, Goodbye</h1></body>
</html>

<!-- end snippet -->

你可以看到额外的字符,如*%被添加了进去。我也尝试过使用ioutil.ReadAll函数,但没有成功。如果有任何建议,将不胜感激。

英文:

I am trying to convert the io.ReadCloser (interface) that I am getting after running the Docker image via Go docker-sdk to []byte for further use.

When I read from the io.ReadCloser using stdcopy.StdCopy to stdout, it prints the data perfectly.

The code stdcopy.StdCopy(os.Stderr, os.Stdout, out) prints:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-html -->

Content-Type: text/html

<html>
<head><title>HTML response</title></head>
<body><h1>Hello, Goodbye</h1></body>
</html>

<!-- end snippet -->

Because I need to send this entire content as a Response I need to convert the content to []byte or string. But, once I convert the io.ReadCloser to []byte or string using any method but stdcopy.StdCopy, it adds a special character to some lines.

The snippet I used to read from out to buf using *bytes.Buffer.ReadFrom:

    buf := new(bytes.Buffer)
	buf.ReadFrom(out)
	fmt.Println(buf.String())

Prints:
<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-html -->

Content-Type: text/html

<html>
*<head><title>HTML response</title></head>
%<body><h1>Hello, Goodbye</h1></body>
</html>

<!-- end snippet -->

As you can see extra characters like * and % are being added. I have also tried ioutil.ReadAll function as well, no luck. Any suggestion would be much appreciated.

答案1

得分: 3

这些是带有一些行前缀的杂乱字节,如*等。

这些杂乱字节似乎是一种自定义流复用协议,允许将STDOUTSTDERR发送到同一连接。

使用stdcopy.StdCopy()可以解释这些自定义头,并通过删除每个数据块的协议头来避免这些杂乱字符。

参考:https://github.com/moby/moby/blob/master/pkg/stdcopy/stdcopy.go#L42

// Write将缓冲区发送到底层写入器。
// 它在缓冲区之前插入前缀头,
// 这样stdcopy.StdCopy就知道在哪里复用输出。
// 它使stdWriter实现io.Writer。

因此,stdcopy.StdCopy是您在使用Docker时的好帮手,也是io.Copy和相关函数的替代品。

以下是一个示例,以帮助您理解:

package main

import (
	"bytes"
	"fmt"
	"io"
	"strings"
)

var resp string = `
Content-Type: text/html
<html>
<head><title>HTML response</title></head>
<body><h1>Hello, Goodbye</h1></body>
</html>`

func main() {
	src := strings.NewReader(resp)
	dst := &bytes.Buffer{}
	_, _ = io.Copy(dst, src)
	fmt.Println(dst.String())
	// 输出:
	//
	// Content-Type: text/html
	// <html>
	// <head><title>HTML response</title></head>
	// <body><h1>Hello, Goodbye</h1></body>
	// </html>
}

func io.Copy(dst io.Writer, src io.Reader)的签名
由于dst*bytes.Buffer)具有Write方法,因此它实现了io.Writer接口,因此可以正常工作。

现在在使用stdcopy.StdCopy()时使用相同的思路,因为签名是相同的。https://pkg.go.dev/github.com/docker/docker/pkg/stdcopy#StdCopy

英文:

Those are stray bytes like *, %, etc. prefixed with some of the lines.

The stray bytes appear to be a custom stream multiplexing protocol, allowing STDOUT and STDERR to be sent down the same connection.

Using stdcopy.StdCopy() interprets these custom headers and those stray characters are avoided by removing the protocol header for each piece of data.

Refer: https://github.com/moby/moby/blob/master/pkg/stdcopy/stdcopy.go#L42

// Write sends the buffer to the underneath writer.
// It inserts the prefix header before the buffer,
// so stdcopy.StdCopy knows where to multiplex the output.
// It makes stdWriter to implement io.Writer.

So, stdcopy.StdCopy is your friend and an alternative for io.Copy and friends when working with Docker.

A sample example to give you an idea:

package main

import (
	&quot;bytes&quot;
	&quot;fmt&quot;
	&quot;io&quot;
	&quot;strings&quot;
)

var resp string = `
Content-Type: text/html
&lt;html&gt;
&lt;head&gt;&lt;title&gt;HTML response&lt;/title&gt;&lt;/head&gt;
&lt;body&gt;&lt;h1&gt;Hello, Goodbye&lt;/h1&gt;&lt;/body&gt;
&lt;/html&gt;`

func main() {
	src := strings.NewReader(resp)
	dst := &amp;bytes.Buffer{}
	_, _ = io.Copy(dst, src)
	fmt.Println(dst.String())
	// Output:
	//
	// Content-Type: text/html
	// &lt;html&gt;
	// &lt;head&gt;&lt;title&gt;HTML response&lt;/title&gt;&lt;/head&gt;
	// &lt;body&gt;&lt;h1&gt;Hello, Goodbye&lt;/h1&gt;&lt;/body&gt;
	// &lt;/html&gt;
}

Signature for: func io.Copy(dst io.Writer, src io.Reader)
As dst (*bytes.Buffer) has a Write method and hence it implements the io.Writer interface and it works.

Now use the same idea when using stdcopy.StdCopy() as the signature is the same. https://pkg.go.dev/github.com/docker/docker/pkg/stdcopy#StdCopy

huangapple
  • 本文由 发表于 2021年6月15日 17:41:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/67983815.html
匿名

发表评论

匿名网友

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

确定