2017-04-03 3 views
1

golang을 배우는 과정에서 여러 이미지 업로드 기능을 가진 웹 앱을 작성하려고합니다.Golang은 멀티 파트를 통해 이미지를 처리하고 Azure로 스트리밍을합니다.

저는 Azure Blob Storage를 사용하여 이미지를 저장하고 있지만 Blob Storage에 대한 멀티 파트 요청에서 이미지를 스트리밍하는 데 문제가 있습니다. 여기

는 지금까지 작성한 핸들러입니다 :

func (imgc *ImageController) UploadInstanceImageHandler(w http.ResponseWriter, r *http.Request, p httprouter.Params) { 
reader, err := r.MultipartReader() 

if err != nil { 
    http.Error(w, err.Error(), http.StatusInternalServerError) 
    return 
} 

for { 
    part, partErr := reader.NextPart() 

    // No more parts to process 
    if partErr == io.EOF { 
     break 
    } 

    // if part.FileName() is empty, skip this iteration. 
    if part.FileName() == "" { 
     continue 
    } 

    // Check file type 
    if part.Header["Content-Type"][0] != "image/jpeg" { 
     fmt.Printf("\nNot image/jpeg!") 
     break 
    } 

    var read uint64 
    fileName := uuid.NewV4().String() + ".jpg" 
    buffer := make([]byte, 100000000) 

    // Get Size 
    for { 
     cBytes, err := part.Read(buffer) 

     if err == io.EOF { 
      fmt.Printf("\nLast buffer read!") 
      break 
     } 

     read = read + uint64(cBytes) 
    } 

    stream := bytes.NewReader(buffer[0:read]) 
    err = imgc.blobClient.CreateBlockBlobFromReader(imgc.imageContainer, fileName, read, stream, nil) 

    if err != nil { 
     fmt.Println(err) 
     break 
    } 
} 

w.WriteHeader(http.StatusOK) 

} 내 연구의 과정에서

, 나는 r.FormFile, ParseMultipartForm를 사용을 통해 읽을 수 있지만하려고 결정한 MultiPartReader 사용 방법을 배우십시오.

이미지를 golang 백엔드에 업로드하고 MultiPartReader를 사용하여 파일을 내 컴퓨터에 저장할 수있었습니다.

현재 Azure에 파일을 업로드 할 수 있지만 파일이 손상됩니다. 파일 크기가 중요하게 보이지만 명확하게 무언가가 작동하지 않습니다.

나는 CreateBlockBlobFromReader에 대한 io.Reader를 만드는 방법을 오해하고 있습니까?

도움을 주시면 감사하겠습니다.

답변

0

Reader은 io.EOF와 유효한 최종 바이트 읽기를 모두 반환 할 수 있으므로 최종 바이트 (cBytes)가 read 총 바이트에 추가되지 않은 것처럼 보입니다. 또한주의 : io.EOF가 아닌 part.Read(buffer)으로 오류가 반환되면 읽기 루프가 종료되지 않을 수 있습니다. 대신 ioutil.ReadAll을 고려하십시오.

CreateBlockBlobFromReader는 Reader를 사용하며 파트는 Reader이므로 파트를 직접 전달할 수 있습니다.

Azure 블록 크기 제한이 이미지보다 작을 수도 있습니다 (Asure blobs 참조).

+0

안녕하세요. 답변 해 주셔서 감사합니다. 나는 부분적으로 CreateBlockBlobFromReader에 직접 전달할 수 있는지 확인하려고했으나 몸 길이가 0이고 따라서 Content-Length와의 불일치가 있다고 Azure에서 오류가 발생합니다 ('읽음'으로 전달하는 내용). . 왜 그런지 아십니까? 나는 직접적으로 다시 통과하려고 노력할 것이다. –

+0

Andrew는 Peter의 도움이되는 답변을 참조하십시오. – Mark

1

@Mark에 따르면, ioutil.ReadAll을 사용하여 내용을 바이트 배열로 읽을 수 있습니다 (아래 코드 참조).

import (
    "bytes" 
    "io/ioutil" 
) 

partBytes, _ := ioutil.ReadAll(part) 
size := uint64(len(partBytes)) 
blob := bytes.NewReader(partBytes) 
err := blobClient.CreateBlockBlobFromReader(container, fileName, size, blob, nil) 

CreateBlockBlobFromReader에 대한 godoc에 따르면, 다음과 같습니다.

이 API 크기> 64 MiB 크기 요청을 거부합니다 (그러나이 제한은 SDK에 의해 확인되지 않음). 더 큰 얼룩을 작성하려면 CreateBlockBlob, PutBlock 및 PutBlockList를 사용하십시오.

크기가 64MB보다 큰 경우 코드 쉐어는 다음과 같습니다.

import "encoding/base64" 

const BLOB_LENGTH_LIMITS uint64 = 64 * 1024 * 1024 

partBytes, _ := ioutil.ReadAll(part) 
size := uint64(len(partBytes)) 
if size <= BLOB_LENGTH_LIMITS { 
    blob := bytes.NewReader(partBytes) 
    err := blobClient.CreateBlockBlobFromReader(container, fileName, size, blob, nil) 
} else { 
    // Create an empty blob 
    blobClient.CreateBlockBlob(container, fileName) 
    // Create a block list, and upload each block 
    length := size/BLOB_LENGTH_LIMITS 
    if length%limits != 0 { 
     length = length + 1 
    } 
    blocks := make([]Block, length) 
    for i := uint64(0); i < length; i++ { 
     start := i * BLOB_LENGTH_LIMITS 
     end := (i+1) * BLOB_LENGTH_LIMITS 
     if end > size { 
      end = size 
     } 
     chunk := partBytes[start: end] 
     blockId := base64.StdEncoding.EncodeToString(chunk) 
     block := Block{blockId, storage.BlockStatusCommitted} 
     blocks[i] = block 
     err = blobClient.PutBlock(container, fileName, blockID, chunk) 
     if err != nil { 
     ....... 
     } 
    } 
    err = blobClient.PutBlockList(container, fileName, blocks) 
    if err != nil { 
     ....... 
    } 
} 

희망이 있습니다.

+0

@Peter에게 답해 주셔서 감사합니다. 왜 CreateBlockBlobFromReader가 독자와 나란히 크기가 필요한지 아십니까? – Mark

+1

@Mark Azure Storage SDK for Golang 또는 다른 언어는 wrappered Storage REST API입니다. ['Put Blob'] (https://docs.microsoft.com/ko-KR/rest/api/storageservices/fileservices/put-blob)/['Put Block'] (https://docs.microsoft. com/en-us/rest/api/storageservices/fileservices/put-block)은 나머지 요청에서'Content-Length' 헤더를 요구합니다. –