2015-02-05 1 views
2

사용자가 다중 파트 폼에서 gzipped 파일을 업로드하는 Go에 작은 webapp를 작성하려고합니다. 응용 프로그램은 파일의 압축을 풀고 응답을 출력합니다. 그러나 응답에 쓰려고 시작할 때 입력 스트림이 손상된 오류가 계속 발생합니다. 응답을 쓰지 않으면 gzip으로 압축되지 않은 입력 스트림에서 읽는 것처럼 문제가 해결됩니다. 여기에 예를 들어 HTTP 처리기는 다음과 같습니다http 응답에 Golang이 입력 읽기를 중단합니까?

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 파일을 읽는다면 왜 응답 쓰기가 중단되지만 일반 텍스트 형식의 파일은 읽지 못합니까? 왜 그것은 전혀 깨지지 않았을까요?

답변

1

HTTP 프로토콜은 전이중이 아니며 요구 기반 응답입니다. 입력을 읽은 후에 만 ​​출력을 보내야합니다.

코드에서 채널에 forrange을 사용합니다. 채널 을 읽으려고 시도하면이 닫히지 만 결코 inputChan을 닫지는 않습니다.

donechan <- true 

그러므로 donechan 블록에서 수신 : EOF에 도달했을 때 당신은 inputChan을 닫아야 할

<-donechan 

을 : 당신이 다음 줄에 도달되지 않습니다 결코 가까운 inputChan 경우

go func() { 
    for scanner.Scan() { 
     inputChan <- scanner.Text() 
    }  
    close(inputChan) // THIS IS NEEDED 
}() 
+0

고마워요! inputChan을 닫는 것이 좋은 지적입니다. 이 코드는 문제를 시연 한 가장 작은 예제 일뿐입니다. 나는 그 게시물을 편집 할 것이다 ... – homesalad