我正在尝试在Go中编写一个小型webapp,用户在多部分表单中上传一个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文件中读取而不是纯文本格式的文件,为什么写入响应会中断?它为什么会破裂?
答案 0 :(得分:1)
HTTP协议不是全双工的:它是基于请求 - 响应的。只有在读完输入后才能发送输出。
在您的代码中,您在频道上使用for
和range
。这将尝试读取频道,直到关闭,但您永远不会关闭inputChan
。
如果您从未关闭inputChan
,则永远不会触及以下行:
donechan <- true
因此从donechan
块接收:
<-donechan
到达EOF时,您必须关闭inputChan
:
go func() {
for scanner.Scan() {
inputChan <- scanner.Text()
}
close(inputChan) // THIS IS NEEDED
}()