HTTP 요청 정보는 클라이언트 측에서 서버에 요청을 보낼 때 포함되는 다양한 데이터, 즉 메타데이터를 의미합니다. 이 정보 크게 헤더와 바디로 나눠져 있으며, 주 정보는 주로 헤더에 들어있는데요.
달리 말하면 이러한 요청 정보는 서버가 클라이언트의 요청을 이해하고 적절한 응답을 생성하는 데 필요한 모든 세부 사항을 담고 있는데요. 해당 요청을 브라우저(크롬 기준)에서 간단히 확인해 보겠습니다.
크롬창에서 F12 버튼을 눌러 개발자 도구를 열고 Network 탭 클릭 생성된 url 정보를 클릭 해당 탭에서 클라이언트의 요청 헤더와 이에 대한 서버의 응답 헤더를 확인할 수 있습니다.
위에서 알아본 헤더의 내용들 중, 중요한 것들만 추려서 설명을 드려보자면 다음과 같습니다.
클라이언트가 요청한 자원의 URL과 쿼리 문자열을 포함하며, method 양식에 따라 보여지는 내용도 달라집니다. 이 정보는 요청이 어떤 자원에 대한 것인지를 나타냅니다.
url의 기본 예시
요청 메소드로, 클라이언트가 서버에 데이터를 요청하는 방식입니다. 주로 GET과 POST 방식으로 나뉘어 집니다.
클라이언트의 요청에 대한 서버의 처리 결과를 나타내는 코드입니다. 1번대는 처리중, 2번대는 성공, 3번대는 추가 작업 처리중, 4번대는 클라이언트측 에러, 5번대는 서버측 에러를 의미합니다.
정확한 나머지 표는 다음 링크에서 확인 가능합니다.
HTTP 요청이나 응답의 본문에 포함된 데이터의 미디어 타입을 명시합니다. 이 헤더는 클라이언트와 서버가 주고받는 데이터의 형식을 명확히 나타냄으로 데이터의 처리를 적절히 수행할 수 있도록 돕는다고 합니다.
응답 본문의 길이(바이트 단위)를 나타냅니다. 클라이언트가 응답 본문의 전체 크기를 알 수 있게 하며, 작은 텍스트의 경우 100 byte - 10,000 byte 사이의 용량을 가지는 반면 파일 다운로드의 경우 1MB - 1,000MB 사이의 용량을 가지기도 합니다.
웹 서버가 클라이언트에게 전송하는 작은 데이터 조각이자, 서버와 클라이언트의 연속성을 이어주는 개념과도 같은데요. 이 데이터 조각은 브라우저에 저장되며, 이후의 요청에 포함되어 서버로 다시 전송됩니다. 쿠키는 상태를 유지하고 사용자 정보를 관리하는 데 사용되는데, 주로 사용자의 특정 세션 ID를 저장하여 사용자가 해당 사이트의 특정 페이지를 재방문시 저장해놓은 쿠키를 이용해 빠른 접근이 가능하도록 합니다.
(자료 출처 : https://raonctf.com/essential/study/web/cookie_connection)
클라이언트의 브라우저 및 플랫폼(운영 체제)에 대한 정보를 담고 있습니다. 서버가 클라이언트의 환경을 이해하는 데 도움을 줍니다.
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.7
- text/html: 클라이언트가 HTML 문서를 수용할 수 있음을 의미합니다.
application/xhtml+xml: 클라이언트가 XHTML 문서를 수용할 수 있음을 의미합니다.
application/xml;q=0.9: 클라이언트가 XML 문서를 수용할 수 있음을 의미합니다. q=0.9의 의미는 전체 우선 순위 중 0.9라는 뜻으로, 1(기본값)이 최대 우선순위입니다. 따라서 다른 문서들보다 우선 순위에서 낮음을 보여줍니다.
image/avif: 클라이언트가 AVIF 이미지 포맷을 수용할 수 있음을 의미합니다.
image/webp: 클라이언트가 WebP 이미지 포맷을 수용할 수 있음을 의미합니다.
image/apng: 클라이언트가 APNG (Animated PNG) 이미지 포맷을 수용할 수 있음을 의미합니다.
/;q=0.8: : 클라이언트가 모든 MIME 타입을 수용할 수 있음을 의미합니다. 이는 text/html, application/xhtml+xml, application/xml과 같은 특정 MIME 타입 외에 모든 콘텐츠 타입을 허용함을 의미하는데, 우선순위가 0.8이므로 이 MIME 타입은 방금 언급한 특정 타입들보다 낮은 우선순위를 가집니다.
application/signed-exchange;v=b3;q=0.7: 클라이언트가 Signed Exchange 포맷을 수용할 수 있음을 의미합니다. 이는 특정 표준을 따르는 콘텐츠를 수용합니다.
요청이 발생한 페이지의 URL을 포함합니다. 서버가 요청의 출처를 알 수 있게 합니다.
서버와의 연결을 재사용하도록 요청하는 헤더입니다. 좀 더 정확히 말하자면 해당 클라이언트의 요청에 의해 서버가 응답을 하고 난 뒤, 트랜잭션(요청-응답의 모든 과정)이 종료되고 나면 서버가 클라이언트측과 네트워크 측면에서 연결을 해야하는지 말아야하는지를 표시할 때 사용되는 헤더인데요.
브라우저마다 표시되는 Connection의 값이 달라지기 때문에 아래의 사진에서 특정 브라우저에 대한 Connection 수치를 확인할 수도 있습니다.
(자료 출처 : https://www.holisticseo.digital/technical-seo/web-accessibility/http-header/connection)
클라이언트가 지원하는 인코딩 방식을 나타냅니다. 서버는 이 정보를 사용하여 응답 본문을 압축할 수 있습니다.
클라이언트가 수신할 수 있는 각 국가의 언어의 수용 정도를 나타냅니다. 서버는 이 정보를 바탕으로 적절한 언어의 콘텐츠를 반환할 수 있습니다. (자세한 내용은 해당 사이트 참조)
헤더에 비해 바디는 그렇게 많은 정보를 나타내고 있지는 않습니다만, 기본적으로 브라우저 개발도구에서 Network 탭에 있는 URL 정보를 클릭하여 확인이 가능하며, 주로 서버에게 보내는 데이터(Paylord)와 사용자에게 보여질 화면의 개요(preview), 응답 페이지의 코드 내용(Response)
서블릿에는 앞서 알아본 헤더 및 바디의 정보들을 세팅할 수 있기도 하고, 또 반대로 출력할 수 있도록 정보를 제공하는 getter, setter 메서드들이 존재하는데요. 해당 메서드들의 종류는 많아서 다 짚기는 어렵고, 현역에서 주로 사용한다는 메서드들을 주로 소개해드리겠습니다.
// 클라이언트로부터 오는 요청을 서버쪽에서 인코딩 할 때의 방식 req.setCharacterEncoding("UTF-8"); // 사용자가 요청할 때 보낸 입력 정보(name)을 받아오기 String name = req.getParameter("name"); // 보여질 컨텐츠의 인코딩 세팅 resp.setContentType("text/html;charset=UTF-8"); // 서버로부터 오는 응답을 클라이언트 쪽에서 인코딩 할 때의 방식 resp.setCharacterEncoding("UTF-8"); // 이름은 user이고 값은 Re_Go인 새로운 쿠키를 생성합니다. Cookie cookie = new Cookie("user", "Re_Go"); // 쿠키의 수명을 세팅합니다. 기본 초단위이며 3600은 1시간을 의미합니다. cookie.setMaxAge(3600); // 응답 정보에 쿠키를 추가합니다. 이후 서버의 요청이 있을 때 다시 서버로 전송됩니다. resp.addCookie(cookie); // 응답 버퍼의 크기(8kb 정도)를 설정합니다. resp.setBufferSize(8192); // 응답 정보가 생성된 날짜와 시간을 나타내며, 응답이 1시간 (밀리초를 환산) 뒤에 만료됨을 의미합니다. resp.setDateHeader("Expires", System.currentTimeMillis() + 3600000); // 응답정보의 헤더에 주어진 이름과 값을 설정합니다. resp.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // 헤더에 주어진 이름과 정수값을 갖도록 응답정보를 헤더에 추가하빈다. resp.setIntHeader("Refresh", 5); // 응답으로 전송될 HTTP 응답에 대한 상태코드를 설정합니다. resp.setStatus(HttpServletResponse.SC_OK); // 서블릿에서 사용자에게 데이터 출력을 위해 관례적으로 사용하는 출력 변수를 사용해 코드의 가독성을 높임 PrintWriter out = resp.getWriter();
// 요청 정보 출력 out.println("<html><body>"); out.println("<h2>요청 정보</h2>"); // 요청 방식 out.println("<p>Request Method: " + req.getMethod() + "</p>"); // URI 정보 out.println("<p>Request URI: " + req.getRequestURI() + "</p>"); // URL 정보 out.println("<p>Request URL: " + req.getRequestURL() + "</p>"); // 프로토콜 정보 out.println("<p>Request Protocol: " + req.getProtocol() + "</p>"); out.println("<p>Request Headers:</p>"); out.println("<ul>"); // 헤더 상세 정보 req.getHeaderNames().asIterator().forEachRemaining(headerName -> { out.println("<li>" + headerName + ": " + req.getHeader(headerName) + "</li>"); }); out.println("</ul>"); // 응답 정보 출력 out.println("<h2>응답 정보</h2>"); // 컨텐츠 타입 out.println("<p>Content Type: " + req.getContentType() + "</p>"); // 문자 인코딩 방식 out.println("<p>Character Encoding: " + req.getCharacterEncoding() + "</p>"); out.print("<form action='index.jsp' method='get'>"); out.print("<button type='submit'>메인 페이지로</button>"); out.print("</form>"); out.println("</body></html>");
// 서블릿의 request 객체 안에 등록된 데이터를 추출하여 반환합니다. Object attributeValue = req.getAttribute("attributeName"); out.println("<h2>Attribute Value</h2>"); out.println("<p>" + (attributeValue != null ? attributeValue.toString() : "No attribute found") + "</p>"); // 클라이언트 -> 서버 방향의 요청시 사용되는 인코딩 방식을 반환합니다. String characterEncoding = req.getCharacterEncoding(); out.println("<h2>Character Encoding</h2>"); out.println("<p>" + (characterEncoding != null ? characterEncoding : "No encoding set") + "</p>"); // 클라이언트 -> 서버 방향으로 서비스 요청시 요청정보 몸체에 포함된 데이터의 길이를 반환 (알 수 없으면 -1을 반환) int contentLength = req.getContentLength(); out.println("<h2>Content Length</h2>"); out.println("<p>" + (contentLength != -1 ? contentLength : "Unknown") + "</p>"); // HTTP 요청에서 특정 파라미터의 값을 추출하는 데 사용되며, 주로 GET 요청의 쿼리 문자열이나 POST 요청의 폼 데이터에서 파라미터 값을 읽을 때 사용. String paramValue = req.getParameter("paramName"); out.println("<h2>Parameter Value</h2>"); out.println("<p>" + (paramValue != null ? paramValue : "No parameter found") + "</p>"); // 서비스를 요청한 클라이언트의 주소를 반환받습니다. String remoteAddr = req.getRemoteAddr(); out.println("<h2>Remote Address</h2>"); out.println("<p>" + (remoteAddr != null ? remoteAddr : "No address found") + "</p>");
// 서비스 요청시 사용한 프로토콜 이름을 반환 받습니다. String scheme = req.getScheme(); out.println("<h2>Scheme</h2>"); out.println("<p>" + (scheme != null ? scheme : "No scheme found") + "</p>"); // 요청을 받은 서버의 이름을 반환 받습니다. String serverName = req.getServerName(); out.println("<h2>Server Name</h2>"); out.println("<p>" + (serverName != null ? serverName : "No server name found") + "</p>"); // 요청을 받은 서버의 포트 번호를 반환 받습니다. int serverPort = req.getServerPort(); out.println("<h2>Server Port</h2>"); out.println("<p>" + serverPort + "</p>"); // 현재 세션을 반환합니다. HttpSession session = req.getSession(); out.println("<h2>Session ID</h2>"); out.println("<p>" + (session != null ? session.getId() : "No session found") + "</p>"); // URL 경로의 일부로 제공된 추가 정보를 반환합니다. 이 정보는 서블릿 매핑에서 URL 패턴의 일부로 설정된 경우, 예를 들어, /path/{id}와 같은 패턴에서 {id} 부분에 해당합니다. String pathInfo = req.getPathInfo(); out.println("<h2>Path Info</h2>"); out.println("<p>" + (pathInfo != null ? pathInfo : "No path info found") + "</p>"); // 모든 쿠키들의 정보(이름과 값을 쌍으로 한)를 반환 받습니다. Cookie[] cookies = req.getCookies(); out.println("<h2>Cookies</h2>"); if (cookies != null) { for (Cookie cookiePart : cookies) { out.println("<p>Cookie: " + cookiePart.getName() + " = " + cookiePart.getValue() + "</p>"); } } else { out.println("<p>No cookies found</p>"); } //getServletContext ServletContext context = req.getServletContext(); out.println("Servlet Context: " + context.getContextPath());