교훈 : 모르는 것은 당연하거니와 아는 것도 그냥 사용하지 말고 개념과 그 구현 방식을 확실히 숙지하고 사용하자
프로젝트를 진행하던 중 이미지 파일 전송과 관련하여 Java로 Http통신을 구현하고 데이터를 InputStream에 담아서 프론트엔드와 백엔드가 통신을 해야할 일이 생겼다.
사실 해당 파트에 충분히 학습하지 않고 검색을 통해 "이렇게 이렇게 하면 된다."정도만 확인한 후 프로젝트 코드에 대입을 하였다.
별 이상없이 동작해서 우선 다른 할 일도 많았기에 커밋을 한 후 다른 작업을 시작하였다.
하지만 커밋 후에 팀원이 동기 처리를 하지 않은 상태에서 getInputStream을 하게 될 경우 아직 응답이 오지 않았는데 없는 데이터가 잡힐 수도있지 않느냐는 질문을 하였고 생각해보니 그 부분에 대해 고려하지 않고 코드를 작성하여 if문으로 응답을 확인한 후 getInputStream을 하는 방향으로 코드를 변경하려고했다.(사실 이때까지도 이게 옳은건지 틀린건지도 분간이 안되고 있었다.)
그때 팀장님께서 해당 커밋에 코멘트를 달아 주셨다..!!
코멘트 내용을 정리해보자면
|
이러하였다.
그래서 이번 기회에 확실히 해당 내용을 숙지하고 또 이러한 상황이 왔을때(아마 프로그래밍을 하다 보면 대부분의 상황이 이렇지 않을까 싶다.) 대처하는 자세를 길러보기 위해 이슈를 정리해보기로 하였다.
차근차근 하나씩 정리해보자.
1. Http 통신에서 InputStream을 얻어서, 읽으려고 한다는 뜻은 무엇일까?
먼저 InputStream이 무엇인지 살펴보자.
- 컴퓨터에 존재하는 모든 데이터는 바이트 단위로 구성되어 있다.
- 바이트 스트림 클래스들은 모두 추상클래스인 InputStream과 OutputStream의 하위 클래스이며,
입출력과 관련된 모든 바이트 스트림은 InputStream과 OutputStream에 있는 메소드를 포함한다.
정의에 따르면 InputStream(OutputStream은 설명에서 빼겠다.)은 컴퓨터에 존재하는 모든 데이터들을 필요에 따라 Java에서 전송하기 위해 사용하는 클래스이다.
InputStream 자체가 무엇인지 알아보았으니 실제 프로젝트에서 사용한 HttpsURLConnection 클래스와 그 클래스의 getInputStream() 메소드에 대해서 알아보자.
- HttpsURLConnection : URLConnection을 상속 받고 있으며 JAVA 소스 내에서 SSL 적용된 사이트에 접근하기 위해, REST Api를 호출하기 위해 사용하게 되며, 결과 데이터를 스트림 형식으로 제공받아 이용이 가능하다. 즉 Application과 URL간의 통신을 위한 작업을 수행한다.
- getInputStream() : HttpsURLConnection 인스턴스를 얻어온 후에 해당 메소드를 사용하면 원격 자원으로부터 데이터를 읽어올 수 있게 된다.
그럼 팀장님이 물어보셨던 InputStream을 읽어서 얻는다는 뜻이 무엇일가? 데이터를 다 보냈지만 읽을 준비를 위해서 InputStream을 얻는다는 뜻일까? 아니면 데이터를 덜 보냈지만 읽을 준비를 위해서 InputStream을 얻는다는 뜻일까? 이 부분은 정말 모르겠어서 학교에서 사용하던 자바 참고서와 블로그 글 등을 참조하여 알아보았다.
stackoverflow에서 비슷한 질문에 대한 답변을 통해 답을 알아낼 수 있었다.
- in the same way that a stream can transfer water between a lake and the ocean without holding a lot of water itself.
해석해보자면 inputstream은 실제 의미의 stream과 같이 많은 양의 물을 stream 자체가 보유하고 있지 않아도 호수와 바다로 물을 이동시킬수있다는 뜻일 것이다. 이와 비슷한 선상에서 이해한다면 팀장님이 물어보신 문제에 대한 답은 "데이터를 덜 보냈지만 읽을 준비를 위해 InputStream을 얻는다는 뜻일 것이다." 또한 InputStream 추상 클래스안에는 available 메소드가 존재하는데 이는 지금 읽어올 수 있는 데이터의 양을 리턴해주는 메소드이다. 이로 미루어 보아도 InputStream을 얻는다는 뜻은 데이터가 덜 준비되어도 읽을 준비를 위해 얻어온다는 의미일 것이다.
2. Http 1.0, 1.1의 Protocol에서 Request가 끝나기 전에 Response를 받을 수 있도록 되어 있나? 또한 ResponseCode를 얻었다는것은 데이터를 모두 보냈다는 뜻?
Http 1.1의 spec 문서를 찾아보았다. Response 부분에 대해서 읽어보았는데 설명이 이렇게 나와있었다.
- After receiving and interpreting a request message, a server responds with an HTTP response message.
request 메세지를 전달받고 해석한 후에 Http response message를 응답해준다고 설명되어있다. 따라서 Http 통신에 있어 Request가 끝나고 난 다음에야 Response를 받을 수 있도록 정의되어있다.
다음으로 Response Code를 얻었다는 것은 데이터를 모두 보냈다는 뜻인지 알아보자.
Response Code는 100 ~ 599번까지 다양하게 존재하며 다양한 경우에 대해서 알맞은 Http 메세지를 보내준다.
이때 적절한 처리가 이루어져서 요청이 성공하면 성공 응답과 함께 결과 값을 보내주기도 하고, 정상적인 처리가 되지 않은 경우에는 실패 응답과 함께 에러 정보를 보내주기도 한다. 따라서 Response Code를 얻었다는 것은 어떤 응답 코드인지 확인하고 그에 따라 데이터가 있는지 없는지를 확인해야한다.
3. Http의 응답코드가 OK가 아닌 경우에는 Body가 없나?
먼저 Http 응답에서의 Body가 무엇인지 찾아보았다.
Http 응답의 마지막 부분에 들어가는 것이 Body(본문)이며 모든 응답에 본문이 들어가지는 않는다고 한다.
201, 204와 같은 상태 코드를 가진 응답에는 보통 본문이 없다.
하지만 이 의미가 응답코드가 OK가 아닌 경우(404, 500 등)에도 Body가 없다는 뜻은 아닐 것이다.
그래서 이 부분은 직접 테스트를 해보았다.
요청이 OK가 아닌 경우에도 이렇게 timestamp, status, error, message, path등의 key값과 그에 따른 정보들을 전달해주는 것을 볼 수 있다.
이렇게 InputStream의 동작 방식과 Http 요청과 그에 따른 응답이 어떻게 상호작용하는지 알아보았다. 아직도 잘 모르고 쓴 글이지만 이렇게 하나하나 확실히 짚고 넘어가야 실력이 오르겠다는 생각이 들었다.
참조
http://wiki.gurubee.net/display/SWDEV/InputStream%2C+OutputStream
https://goddaehee.tistory.com/268
https://derveljunit.tistory.com/155
https://docs.oracle.com/javase/7/docs/api/java/net/URLConnection.html
https://tools.ietf.org/html/rfc2616#page-39
https://developer.mozilla.org/ko/docs/Web/HTTP/Messages
'개발 지식' 카테고리의 다른 글
파일 마지막에 빈 줄을 넣는 이유 (0) | 2021.07.02 |
---|---|
POST vs PUT (0) | 2021.02.15 |
포트포워딩 하는 법 (0) | 2020.12.10 |
IP 주소 (0) | 2020.12.10 |
Spring Boot에서 save 메소드의 동작 원리 (0) | 2020.12.07 |