Go로 만드는 웹 2 - File upload

솔다·2023년 1월 28일
0

Go로 File upload 가능한 서버 구성하기

지난 번 포스팅에서는 기초 web server를 구성했고, Json 방식으로 데이터를 주고받는 것까지 구현했다. 이번에는 file을 웹을 통해서 실제로 서버에 업로드 할 수 있는 웹 페이지와 서버를 구성해보고자 한다.

기초적인 기능이 들어간 코드는 아래와 같다.

func uploadsHandler(w http.ResponseWriter, r *http.Request) {
	uploadfile, header, err := r.FormFile("upload_file")
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, err)
		return
	}
	defer uploadfile.Close()

	dirname := "./uploads"
	os.MkdirAll(dirname, 0777)
	filepath := fmt.Sprintf("%s/%s", dirname, header.Filename)
	file, err := os.Create(filepath)
	defer file.Close()
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err)
		return
	}
	io.Copy(file, uploadfile)
	w.WriteHeader(http.StatusOK)
	fmt.Fprint(w, filepath)
}

이 코드를 보면, file을 서버로 전송했을 때, 서버가 어떤 메커니즘으로 처리하는지 알 수 있다.

파일을 저장하고자 하는 directory를 생성하고(기존에 없다면), 이 경로에 새로운 파일인 file을 생성한다. 이후에 서버에서 받은 파일을 request의 FormFile()로 연 뒤에 io.Copy()함수로 데이터를 복사한다.

이때, 당연히 defer를 이용해 새롭게 생성한 fileuploadFile을 Close() 해줘야 한다.

server에 file_upload 테스트하기

test를 위한 코드가 더 길다... 그래도, 원리 자체는 전에 server에서 json을 테스트한거랑 크게 다르지 않다.

func TestUploadTest(t *testing.T) {
	assert := assert.New(t)
	path := "C:/Users/dasol/Downloads/gogo.png"
	file, _ := os.Open(path)
	defer file.Close()

	os.RemoveAll("./uploads")

	buf := &bytes.Buffer{}
	writer := multipart.NewWriter(buf)
	multi, err := writer.CreateFormFile("upload_file", filepath.Base(path))
	assert.NoError(err)
	io.Copy(multi, file)
	writer.Close()

	res := httptest.NewRecorder()
	req := httptest.NewRequest("POST", "/uploads", buf)
	req.Header.Set("Content-type", writer.FormDataContentType())

	uploadsHandler(res, req)
	assert.Equal(http.StatusOK, res.Code)

	uploadFilePath := "./uploads/" + filepath.Base(path)
	_, erro := os.Stat(uploadFilePath)
	assert.NoError(erro)

	uploadFile, _ := os.Open(uploadFilePath)
	originFile, _ := os.Open(path)
	defer uploadFile.Close()
	defer originFile.Close()

	//파일 내용물을 read로 읽고 같은지 확인
	uploadData := []byte{}
	originData := []byte{}

	uploadFile.Read(uploadData)
	originFile.Read(originData)

	assert.Equal(originData, uploadData)
}

test 를 위해서 해줘야 하는 코드는 위와 같다. 파일을 업로드 하는 만큼 임시로 파일을 업로드하기 위해서 해주어야 하는 일들이 많은데, 순서대로 확인해보자.

먼저 우리가 테스트로 업로드할 파일의 경로를 설정하고 직접 열어준다.(당연히 열어준 뒤에는 defer로 function이 종료될 때 닫아주어야 한다)

이후 buffer를 하나 임시로 생성해서 multipart.NewWriter의 인자로 넣어준다.
웹으로 파일을 전송할때는 MIME 포맷으로 전송하는데(email로 주고 받을때도 사용함) 이를 위해서 우리가 직접 테스트를 만들어줄때는, multipart를 사용하면 form을 생성해줄 수 있다.

생성된 폼에 Copy()를 이용해 내용을 넣어주고, request와 response를 만들어서 함수를 실행하고, assert()를 이용해서 검사한다.

각 파일마다 데이터를 읽어올 buffer를 만들어주고, data를 읽어온뒤에 두 파일이 동일한지 assert.Equal()로 확인하면 된다.

0개의 댓글