HTTP / GET / POST

HTTP / GET / POST

교과서 기초 개념 정리

 

공부한걸 틈틈이 포스팅하며 정리와 복습을 해야 하는데,

워낙 학습량이 많다 보니 포스팅하는 게 생각보다 쉽지가 않다.

그래도 미래의 나를 위해서 힘들더라도 조금씩이나마 꾸준히 포스팅해야겠다고 생각했다.

Servlet을 처음 공부할 때 DNS & HTTP 프로토콜GET/ Post 방식에 대해 공부했었는데,

당시에는 “아~ 이런 것도 있구나” 하고 가볍게 넘어갔었다.

그때는 자바에서 웹 통신을 하기 위한 입출력 장치가 없기 때문에

WAS의 Servlet을 가져와 입출력 장치(HttpRequest, HttpResponse)를 자바로 구현한다는 게 보다 더 핵심적인 기능이라고 생각했기 때문이다.

 

물론 이 생각은 아직도 유효하다..!

 

사실 이때 처음 안 사실이 하나 있는데,

그게 뭐냐 하면 자바는 javax(자바 extension)라는 확장 패키지를 통해

이기종 시스템의 기능을 자바에서 구현한다는 사실이었다.

대표적인 녀석으로 Swing이라는 자바의 UI 라이브러리가 있겠다.

그 유명하고 우리가 많이 사용하는 인텔리제이(IntelliJ)가 바로 이 Swing으로 만들어진 대표적인 프로그램이다.

 

아무튼 각설하고, AJAX(Asynchronous javascript and XML)를 처음 구현하고

Spring Security를 막 사용할 때 이 GETPost에 대해 진지하게 찾아보게된 계기가 있는데 그 이유가 뭐냐하면 통신이 되질 않아서였다.

Spring SecurityXSS 공격을 방지하기 위해 Post 방식으로 통신할 경우 매번 CSRF Token을 주고받아야 했고

HTTP 헤더에 Content Type을 명시해야 했는데 당시엔 이를 몰랐기 때문이다.

GET은 설계 자체가 조회를 위해 만들어진 방식이기 때문에 위의 내용과는 상관이 없는 것 같았다.

아무튼 매번 이렇게 통신이 안돼 구글링을 하느니 차라리 이걸 내가 확실하게 이해해놔야 겠다는 생각이 강하게 들었었다.

 

HTTP


HTTP는 웹 통신을 위한 국제적인 약속의 일종이다.

웹 개발자라면 모두 이 HTTP의 요구사항에 맞추어 개발을 해야 한다.

이런 약속을 어겨서 모두가 피해를 보는 경우가 있는데

범주는 약간 다르지만 웹 브라우저 표준을 지키지 않는 대표적인 예가 있다.

바로 MSIE(Internet Explorer)이다. (크로스 브라우징 이슈)

 

이 HTTP는 HeaderBody로 구성되는데

HTTP Header는 General HeaderRequest/Response Header 로 나뉜다.

General Header에는 간략한 요청정보와 통신의 상태 코드등의 정보가 들어있고

Request/Response Header에는 더 자세한 내용들이 담겨있으며,

HTTP Body에는 요청 정보에 대한 상세한 내용이 담겨있다.

HTML, JSON, XML 등의 메시지가 들어간다.

 

GET


  -General Header
  Request URL: http://localhost:8090/member/user-ask-list?pageNum=1&pageNumReview=1&amount=10
  Request Method: GET
  Status Code: 200 
  Remote Address: [::1]:8090
  Referrer Policy: strict-origin-when-cross-origin

  -Request Header
  Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
  Accept-Encoding: gzip, deflate, br
  Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
  Connection: keep-alive
  Cookie: JSESSIONID=B8E6104ABE710304CEDBD46DE2FDB17F
  Host: localhost:8090
  Referer: http://localhost:8090/member/my-page
  sec-ch-ua: "Google Chrome";v="87", " Not;A Brand";v="99", "Chromium";v="87"
  sec-ch-ua-mobile: ?0
  Sec-Fetch-Dest: document
  Sec-Fetch-Mode: navigate
  Sec-Fetch-Site: same-origin
  Sec-Fetch-User: ?1
  Upgrade-Insecure-Requests: 1
  User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36

  -Query String 파라미터s
  pageNum: 1
  pageNumReview: 1
  amount: 10

GET은 서버로부터 데이터를 조회할 때 사용하도록 만들어진 녀석이다.

이 녀석은 멱등(Idempotent) 하게 설계되었다.

📜 멱등(Idempotent)

수학이나 전산학에서 연산의 한 성질을 나타내는 것으로, 연산을 여러 번 적용하더라도 결과가 달라지지 않는 성질 동일한 연산을 여러 번 수행해도 동일한 값이 나와야 함을 의미함

GET의 특징

📜 파라미터가 URL을 통해 외부에 노출된다


http://localhost:8090/member/user-ask-list?pageNum=1&pageNumReview=1&amount=10

위와 같은 URL이 GET방식의 URL인데 user-ask-list 다음 ?로 시작하는 부분이 있다.

?는 이제부턴 파라미터라는 뜻이고 &는 파라미터를 구분하는 구분자다.

각 파라미터는 키(Key)=값(Value)의 쌍으로 표시된다.

이 파라미터의 표시를 쿼리스트링(Querystring) 이라고 부른다.

 

결론적으로 위 URL의 파라미터는

pageNum=1, pageNumReview=1, amount=10

이며, 어떤 요청(Request)에 위와 같은 값들을 서버로 함께 보내는 것이다.

서버에서는 이 값들을 전달받아 비즈니스 로직을 처리하여 처리된 데이터를 Client에게 되돌려준다.

실제로 위 코드블럭을 보면 최하단에

 -Query String parameters  
  pageNum: 1  
  pageNumReview: 1  
  amount: 10

라는 문구를 볼 수 있다.

 

📜 쿼리스트링(Querystring)의 길이는 한계가 있다


웹 브라우저에 입력되는 URL의 길이는 무한할 수 없다

 

📜 브라우저에 캐시 될 수 있다


조회(GET) 시 주로 js, css, image 등의 크기가 크고 변동될 사항이 적은 정적 파일들을 가져오기 때문에

브라우저는 이 파일들을 브라우저가 깔린 하드디스크 경로에 저장해 두고

이를 재사용하기 때문에 통신속도의 향상을 기대할 수 있다.

다만 캐시 된 파일을 사용하기 때문에 수정사항이 생겨 정적 파일에 변동사항이 생겼음에도

변경되기 전의 파일이 웹 브라우저에 캐시 되어있어 변경사항이 반영되지 않는 경우가 있을 수 있는데,

이때는 당황하지 말고 브라우저의 캐시를 초기화시켜주면 반영된 결과를 볼 수 있을 것이다.

(브라우저 강력 새로고침 기능)

 

POST


  -General Header
  Request URL: http://localhost:8090/login
  Request Method: POST
  Status Code: 200 
  Remote Address: [::1]:8090
  Referrer Policy: strict-origin-when-cross-origin

  -Request Header
  Accept: application/json, text/자바script, */*; q=0.01
  Accept-Encoding: gzip, deflate, br
  Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
  Connection: keep-alive
  Content-Length: 37
  Content-Type: application/x-www-form-urlencoded; charset=UTF-8
  Cookie: JSESSIONID=0000000038AB0E7D556C6D68F0A
  Host: localhost:8090
  Origin: http://localhost:8090
  Referer: http://localhost:8090/member/login-page
  sec-ch-ua: "Google Chrome";v="87", " Not;A Brand";v="99", "Chromium";v="87"
  sec-ch-ua-mobile: ?0
  Sec-Fetch-Dest: empty
  Sec-Fetch-Mode: cors
  Sec-Fetch-Site: same-origin
  User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36
  X-CSRF-TOKEN: 61a8cec2-efff-47ce-b644-77cd5425ac3c
  X-Requested-With: XMLHttpRequest

  -Form Data
  memberId: tester
  memberPw: QWERASDF!

이 녀석은 주로 데이터의 입력/수정을 위해 사용된다.

그래서 GET과 반대로 Non-Idempotent 하게 설계되었다.

항상 값이 변할 수 있다는 이야기이다.

 

POST는 GET과 다르게 파라미터의 크기에 제한이 없다.

http://localhost:8090/login

위는 POST방식의 URL인데 보다시피 외부로 노출된 파라미터가 없다.

주의할 점은 명확하게 Content Type을 명시해줘야 타입 추론으로 인한 장애가 발생하지 않는다.

이를 명시하지 않을 경우 통신에 실패하는 경우가 생길 수 있다.

(나는 이걸 명시해주지 않아서 AJAX 구현 할 때 물을 먹었다)

 

또한 파라미터가 바디에 숨겨진다고는 하나 개발자 도구나, 피들러같은 툴을 사용하여 작정하고 보려고 하면 쉽게 볼 수 있기 때문에

보안을 생각한다면 추가적인 암호화를 반드시 해줘야 한다.

 

위 코드블럭은 웹 브라우저의 개발자 도구로 본 POST방식 Request Header의 상세정보이다.

보다시피 최하단에

\-Form Data-Form Data  
memberId: tester  
memberPw: QWERASDF!

라 하여 서버에 보내는 정보를 눈으로 바로 확인할 수 있음을 알 수 있다.


© 2022. All rights reserved.