Golang 写入 http 响应会中断输入读取?
Golang writing to http response breaks input reading?
我正在尝试用 Go 编写一个小型网络应用程序,用户可以在其中以多部分形式上传 gzip 文件。该应用程序解压缩并解析文件并将一些输出写入响应。但是,当我开始写入响应时,我将 运行 保存为输入流看起来已损坏的错误。不写入响应解决了这个问题,就像从非 gzip 压缩的输入流中读取一样。这是一个示例 http 处理程序:
func(w http.ResponseWriter, req *http.Request) {
//Get an input stream from the multipart reader
//and read it using a scanner
multiReader, _ := req.MultipartReader()
part, _ := multiReader.NextPart()
gzipReader, _ := gzip.NewReader(part)
scanner := bufio.NewScanner(gzipReader)
//Strings read from the input stream go to this channel
inputChan := make(chan string, 1000)
//Signal completion on this channel
donechan := make(chan bool, 1)
//This goroutine just reads text from the input scanner
//and sends it into the channel
go func() {
for scanner.Scan() {
inputChan <- scanner.Text()
}
close(inputChan)
}()
//Read lines from input channel. They all either start with #
//or have ten tab-separated columns
go func() {
for line := range inputChan {
toks := strings.Split(line, "\t")
if len(toks) != 10 && line[0] != '#' {
panic("Dang.")
}
}
donechan <- true
}()
//periodically write some random text to the response
go func() {
for {
time.Sleep(10*time.Millisecond)
w.Write([]byte("write\n some \n output\n"))
}
}()
//wait until we're done to return
<-donechan
}
奇怪的是,这段代码每次都会崩溃,因为它总是遇到一行少于 10 个标记的行,尽管每次都在不同的位置。注释掉写入响应的行解决了这个问题,从非 gzip 压缩的输入流中读取也是如此。我错过了一些明显的东西吗?如果从 gzip 文件而不是纯文本格式的文件读取,为什么写入响应会中断?为什么它会破裂?
HTTP 协议不是全双工的:它是基于请求-响应的。您应该只在阅读完输入后才发送输出。
在您的代码中,您在频道上使用 for
和 range
。这将尝试读取通道 直到 它被关闭,但你永远不会关闭 inputChan
.
如果您从不关闭 inputChan
,则永远不会到达以下行:
donechan <- true
因此从 donechan
块接收:
<-donechan
到达 EOF 时必须关闭 inputChan
:
go func() {
for scanner.Scan() {
inputChan <- scanner.Text()
}
close(inputChan) // THIS IS NEEDED
}()
我正在尝试用 Go 编写一个小型网络应用程序,用户可以在其中以多部分形式上传 gzip 文件。该应用程序解压缩并解析文件并将一些输出写入响应。但是,当我开始写入响应时,我将 运行 保存为输入流看起来已损坏的错误。不写入响应解决了这个问题,就像从非 gzip 压缩的输入流中读取一样。这是一个示例 http 处理程序:
func(w http.ResponseWriter, req *http.Request) {
//Get an input stream from the multipart reader
//and read it using a scanner
multiReader, _ := req.MultipartReader()
part, _ := multiReader.NextPart()
gzipReader, _ := gzip.NewReader(part)
scanner := bufio.NewScanner(gzipReader)
//Strings read from the input stream go to this channel
inputChan := make(chan string, 1000)
//Signal completion on this channel
donechan := make(chan bool, 1)
//This goroutine just reads text from the input scanner
//and sends it into the channel
go func() {
for scanner.Scan() {
inputChan <- scanner.Text()
}
close(inputChan)
}()
//Read lines from input channel. They all either start with #
//or have ten tab-separated columns
go func() {
for line := range inputChan {
toks := strings.Split(line, "\t")
if len(toks) != 10 && line[0] != '#' {
panic("Dang.")
}
}
donechan <- true
}()
//periodically write some random text to the response
go func() {
for {
time.Sleep(10*time.Millisecond)
w.Write([]byte("write\n some \n output\n"))
}
}()
//wait until we're done to return
<-donechan
}
奇怪的是,这段代码每次都会崩溃,因为它总是遇到一行少于 10 个标记的行,尽管每次都在不同的位置。注释掉写入响应的行解决了这个问题,从非 gzip 压缩的输入流中读取也是如此。我错过了一些明显的东西吗?如果从 gzip 文件而不是纯文本格式的文件读取,为什么写入响应会中断?为什么它会破裂?
HTTP 协议不是全双工的:它是基于请求-响应的。您应该只在阅读完输入后才发送输出。
在您的代码中,您在频道上使用 for
和 range
。这将尝试读取通道 直到 它被关闭,但你永远不会关闭 inputChan
.
如果您从不关闭 inputChan
,则永远不会到达以下行:
donechan <- true
因此从 donechan
块接收:
<-donechan
到达 EOF 时必须关闭 inputChan
:
go func() {
for scanner.Scan() {
inputChan <- scanner.Text()
}
close(inputChan) // THIS IS NEEDED
}()