요청정보 처리 - HttpServletRequest
이번 절에서는 요청정보가 무엇인지, 그리고 요청정보 추출과 관련된 주요 API들의 종류와 기능에 대해 알아보겠습니다.
브라우저에 적절한 URL 문자열을 이용하여 웹서버에 서블릿 수행을 요청할 때 일정한 형식의 다양한 정보를 서버로 전달하는데요. 이때 클라이언트가 서버로 전달하는 요청정보들은 다음과 같습니다.
- 클라이언트의 IP 주소, 포트 번호
- 클라이언트가 전송한 요청 헤더 정보(클라이언트에서 처리 가능한 문서 타입의 종류, 클라이언트 프로그램 정보, 처리 가능한 문자셋 정보, 쿠키 정보)
- 요청 방식, 요청 프로토콜의 종류와 버전, 요청하는 파일의 URI, 요청받은 서버의 정보
- 서버의 호스트 이름, 포트 번호
- 사용자가 서블릿 요청 시 추가로 전달한 정보
- 질의(Query) 문자열(웹서버에 서비스를 요청하면서 추가로 전달한 name=value 형태의 데이터)
위와 같은 다양한 요청정보는 HttpServletRequest 인터페이스의 getXXX() 메소드를 통해 추출할 수 있고, HttpServletRequest는 service()나 doGet() 또는 doPost() 메소드의 첫 번째 인자로 전달됩니다. 클라이언트가 보낸 요청정보를 처리할 때 사용하는 HttpServletRequest 인터페이스는 ServletRequest를 상속받습니다.
ServletRequest의 주요 메소드
함수 | 기능 |
---|---|
Object getAttribute(String name) | ServletRequest 객체 안에 등록된 데이터를 추출하여 반환한다. |
Enumeration getAttributeNames() | ServletRequest 객체 안에 등록된 데이터들의 이름 전부를 하나의 Enumeration 객체에 담아서 반환한다. |
String getCharacterEncoding() | 클라이언트가 서버에 서비스를 요청할 때 사용한 문자들의 인코딩 문자셋을 반환한다. |
int getContentLength() | 서비스 요청 시 보낸 요청정보 몸체에 포함된 데이터의 길이를 반환한다. 만약 길이를 알 수 없을 때는 -1를 반환한다. |
ServletInputStream getInputStream() | 요청정보 몸체로부터 바이너리 데이터를 읽어들이기 위해 한 번에 한 줄씩 읽을 수 있는 ServletInputStream 객체를 반환한다. |
String getParameter(String name) | 클라이언트가 보낸 질의 문자열 중에서 인자로 지정된 name과 일치하는 것을 찾아 name의 value를 반환한다. |
Enumeration< String> getParameterNames() | 클라이언트가 서버로 보낸 질의 문자열들의 이름을 하나의 Enumeration 객체에 담아서 반환한다. |
String[] getParameterValues(String name) | 클라이언트가 서버로 보낸 질의 문자열 중에서 인자로 지정된 name과 일치하는 모든 값을 찾아 하나의 String 타입의 배열에 담아 반환한다. |
String getProtocol() | 클라이언트가 서버에 서비스를 요청하면서 사용한 프로토콜 정보를 반환한다. |
BufferedReader getReader() | 요청정보 몸체로부터 문자 인코딩에 따라 텍스트를 읽어들이기 위한 BufferedReader 객체를 반환한다. |
String getRemoteAddr() | 서버에 서비스를 요청한 클라이언트의 IP 주소를 반환한다. |
String getScheme() | 서비스 요청 시 사용한 http, https, 또는 ftp 등과 같은 프로토콜 이름을 반환한다. |
String getServerName() | 서비스를 요청받은 서버의 이름을 반환한다. |
int getServerPort() | 클라이언트의 서비스를 요청받은 서버 포트 번호를 반환한다. |
ServletContext getServletContext() | 서버가 시작될 때 웹 애플리케이션 단위로 생성된 ServletContext 객체의 주소를 추출하여 반환한다. |
void removeAttribute(String name) | ServletRequest 객체에 setAttribute(name) 메소드를 이용하여 등록된 데이터를 삭제한다. |
void setAttribute(String name, Object o) | 클라이언트의 또 다른 서비스 요청에서도 계속해서 사용하고 싶은 데이터는 서버에 저장해야 하는데 ServletRequest 객체 안에 저장(등록)해준다. |
void setCharacterEncoding(String env) | 클라이언트가 요청정보 몸체에 포함해서 보내는 문자열들을 지정된 문자셋을 이용해 인코딩해준다. |
ServletRequest 객체는 네트워크 기반에서 사용되는 기본적인 메소드들로 구성되어 있으며, HTTP 프로토콜에 기반하는 세션이나 쿠키와 같은 정보를 추출하는 메소드는 지원하지 않습니다. HTTP 프로토콜 기반의 기능을 지원하는 메소드는 HttpServletRequest 객체에서 확장 지원하고 있습니다.
다음은 HttpServletRequest에서 추가된 메소드입니다.
HttpServletRequest의 메소드
함수 | 기능 |
---|---|
String getHeader(String headerName) | HTTP 요청 헤더에 지정된 headerName의 값을 문자열로 반환한다. 만일 HTTP 요청 헤더에 headerName의 값이 없으면 null을 반환한다. |
Enumeration getHeaderNames() | HTTP 요청 헤더에 포함된 모든 헤더의 이름을 Enumeration으로 반환한다. |
Enumeration getHeaders(String headerName) | HTTP 요청 헤더에 포함된 headerName의 모든 값을 Enumeration으로 반환한다. |
int getIntHeader(String headerName) | HTTP 요청 헤더에 포함된 headerName의 값을 int로 반환한다. 지정된 headerName의 값을 int로 변환할 수 없을 때 NumberFormat Exception이 발생하고, headerName 헤더가 HTTP 요청 헤더에 없을 때 -1을 반환한다. |
long getDateHeader(String headerName) | HTTP 요청 헤더에 포함된 headerName의 값을 밀리초로 변환하여 long으로 반환한다. 지정된 header의 값을 int로 변환할 수 없을 때 IllegalArgumentException이 발생하고, headerName 헤더가 HTTP 요청 헤더에 없을 때 -1을 반환한다. |
String getPathInfo() | 클라이언트가 서비스 요청 시 보낸 요청 URL의 뒷부분에 있는 path 정보를 반환한다. |
HttpSession getSession() | 서비스를 요청한 클라이언트가 사용하는 HttpSession 객체를 반환한다. 만일 반환할 HttpSession 객체가 없으면 새로 생성하여 반환한다. |
HttpSession getSession(boolean create) | 서비스를 요청한 클라이언트가 사용하는 HttpSession 객체를 반환한다. 만일 반환한 HttpSession 객체가 없으면 getSession(true)이면 새로 생성하여 반환한다. 그러나 getSession(false)이면 HttpSession 객체를 새로 생성하지 않고 null을 반환한다. |
String getRequestedSessionId() | 서비스를 요청한 클라이언트가 사용하는 HttpSession의 ID를 반환한다. |
boolean isRequestedSessionIdValid() | 서비스를 요청한 클라이언트가 사용하는 HttpSession 객체가 유효한지를 판단한다. |
boolean isRequestedSessionIdFromCookie() | 서비스를 요청한 클라이언트가 사용하는 HttpSession의 ID가 쿠키로 전달되면 true, 그렇지 않다면 false를 반환한다. |
boolean isRequestedSessionIdFromURL() | 서비스를 요청한 클라이언트가 사용하는 HttpSession의 ID가 URL에 포함되면 true, 그렇지 않다면 false를 반환한다. |
Cookie[] getCookies() | 서비스를 요청받은 서버가 서비스를 요청한 클라이언트에게 이전에 보낸 모든 쿠키를 추출한다. |
String getRequestURI() | 클라이언트가 서비스 요청 시 보낸 URL에서 URI 부분만 반환한다. |
String getQueryString() | 클라이언트가 GET 방식으로 서버에 보낸 질의 문자열들을 모두 추출하여 반환한다. |
String getMethod() | 클라이언트가 서비스를 요청할 때 요청한 방식의 이름을 반환한다. |
String getPathTranslated() | 클라이언트가 서비스 요청 시 보낸 URL의 경로 정보를 절대경로(path)로 변경하여 반환한다. |
네트워크 정보
HttpServletRequest 인터페이스에서 제공하는 메소드 중에서 서버와 클라이언트의 네트워크 정보를 추출하는 메소드들을 실행한 후 결괏값을 확인하는 예제를 작성해보겠습니다. NetInfoServlet.java라는 이름으로 새로운 클래스 파일을 만들고 다음과 같은 코드를 작성합니다.
package com.edu.test;
import java.io.*;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
@WebServlet("/netInfo")
public class NetInfoServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException {
rsp.setContentType("text/html;charset=EUC-KR");
PrintWriter out = rsp.getWriter();
out.print("<html><head><title>Request 정보 출력 Servlet</title></head>");
out.print("<body>");
out.print("<h3>네트워크 관련 요청 정보</h3>");
out.print("Request Scheme: " + req.getScheme() + "<br/>");
out.print("Server Name: " + req.getServerName() + "<br/>");
out.print("Server Address: " + req.getLocalAddr() + "<br/>");
out.print("Server Port: " + req.getServerPort() + "<br/>");
out.print("Client Address: " + req.getRemoteAddr() + "<br/>");
out.print("Client Host: " + req.getRemoteHost() + "<br/>");
out.print("Client Port: " + req.getRemotePort() + "<br/>");
out.print("</body></html>");
out.close();
}
}
[실행 결과]
URL 정보
이번에는 HttpServletRequest 인터페이스에서 제공하는 메소드 중에서 URL 정보를 추출하는 메소드들을 실행한 후 결괏값을 확인하는 예제를 작성해보겠습니다. URLInfoServlet.java라는 이름으로 새로운 클래스 파일을 만들고 다음과 같은 코드를 작성합니다.
package com.edu.test;
import java.io.*;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
@WebServlet("/urlInfo")
public class URLInfoServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException {
rsp.setContentType("text/html;charset=EUC-KR");
PrintWriter out = rsp.getWriter();
out.print("<html><head><title>Request 정보 출력 Servlet</title></head>");
out.print("<body>");
out.print("<h3>요청 방식과 프로토콜 정보</h3>");
out.print("Request URI: " + req.getRequestURI() + "<br/>");
out.print("Request URL: " + req.getRequestURL() + "<br/>");
out.print("Context Path: " + req.getContextPath() + "<br/>");
out.print("Request Protocol: " + req.getProtocol() + "<br/>");
out.print("Servlet Path: " + req.getServletPath() + "<br/>");
out.print("</body></html>");
out.close();
}
}
[실행 결과]
모든 헤더 정보
HTTP 프로토콜의 요청정보는 헤더와 몸체(body)로 구성되어 있고, 헤더는 두 번째 줄 이후부터는 "name:value" 형태로 헤더 정보들이 들어있습니다. HttpServletRequest 인터페이스에서 제공하는 메소드들을 이용하여 요청정보의 헤더 정보들을 추출한 후 결괏값을 확인하는 예제를 작성해보겠습니다. HeaderInfoServlet.java라는 이름으로 새로운 클래스 파일을 만들고 다음과 같은 코드를 작성합니다.
package com.edu.test;
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
@WebServlet("/headerInfo")
public class HeaderInfoServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException {
rsp.setContentType("text/html;charset=EUC-KR");
PrintWriter out = rsp.getWriter();
out.print("<html><head><title>Request 정보 출력 Servlet</title></head>");
out.print("<body>");
out.print("<h3>요청 헤더 정보</h3>");
Enumeration<String> em = req.getHeaderNames();
while(em.hasMoreElements()) {
String s = em.nextElement();
out.println(s + ": " + req.getHeader(s) + "<br/>");
}
out.print("</body></html>");
out.close();
}
}
[실행 결과]
추가 정보
HttpServletRequest 인터페이스에서 제공하는 메소드 중에서 질의(Query) 문자열이나 추가 경로 정보를 추출하는 메소드들을 실행한 후 결괏값을 확인하는 예제를 작성하겠습니다. AdditionalInfoServlet.java라는 이름으로 새로운 클래스 파일을 만들고 다음과 같은 코드를 작성합니다.
package com.edu.test;
import java.io.*;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
@WebServlet("/addInfo")
public class AdditionalInfoServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException {
rsp.setContentType("text/html;charset=EUC-KR");
PrintWriter out = rsp.getWriter();
out.print("<html><head><title>Request 정보 출력 Servlet</title></head>");
out.print("<body>");
out.print("<h3>추가적인 요청 정보</h3>");
out.print("Request Method: " + req.getMethod() + "<br/>");
out.print("Path Info: " + req.getPathInfo() + "<br/>");
out.print("Path Translated: " + req.getPathTranslated() + "<br/>");
out.print("Query String: " + req.getQueryString() + "<br/>");
out.print("Content Length: " + req.getContentLength() + "<br/>");
out.print("Content Type: " + req.getContentType() + "<br/>");
out.print("</body></html>");
out.close();
}
}
[실행 결과]
https://kgvovc.tistory.com/29에서 서블릿을 요청할 수 있는 방법은 두 가지 방법이 있다고 했습니다. web.xml 파일에 설정하는 방법과 @WebServlet 어노테이션을 이용하는 방법입니다. AdditionalInfoServlet 예제는 @WebServlet("/addInfo") 어노테이션으로 설정하여 실행했습니다.
이번에는 web.xml 파일 설정으로 실행해봅시다. 먼저 AdditionalInfoServlet.java 파일에서 이전에 작성한 @WebServlet("/addInfo") 어노테이션 설정 부분을 주석 처리합니다.
// @WebServlet("/addInfo")
이어서 web.xml 파일을 다음처럼 설정합니다.
~ 생략 ~
<servlet>
<servlet-name>addInfo</servlet-name>
<servlet-class>com.edu.test.AdditionalInfoServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>addInfo</servlet-name>
<url-pattern>/addInfo/*</url-pattern>
</servlet-mapping>
~ 생략 ~
위의 코드 중 <url-pattern> 태그 안에 /addInfo/*
를 입력했는데요. 여기서 *라는 문자는 일반 문자가 아니고 특수 문자로서, * 기호가 있는 자리에 어떤 경로(path)가 와도 상관이 없다는 의미입니다. 따라서, 클라이언트로부터 요청된 URL이 http://localhost:8080/edu/addInfo
로 시작하는 조건만 만족한다면, addInfo 서블릿을 실행한다는 의미죠.
따라서 다음의 요청 URL들은 모두 addInfo 서블릿을 실행합니다.
http://localhost:8080/edu/addInfo/a
http://localhost:8080/edu/addInfo/a/b
http://localhost:8080/edu/addInfo/a/b/c
각 요청 URL로 addInfo 서블릿을 실행한 결과는 다음과 같습니다.
[실행 결과]
URL에 ? 기호와 함께 name=value&name=value 형태로 정보를 추가할 수 있고, 이렇게 URL에 추가된 정보를 getQueryString() 메소드로 추출할 수 있다는 것을 확인했습니다.
또, Content Length가 -1인 이유는 GET 방식으로 전달된 요청정보의 몸체에는 어떤 데이터도 없기 때문에 -1을 반환합니다. 같은 이유로 요청정보 몸체의 문서타입을 구하는 Content Type 역시 null을 반환합니다.
'웹 프로그래밍 > Servlet & JSP' 카테고리의 다른 글
Servlet doGet(), doPost() 메소드 구현과 질의 문자열 추출 (0) | 2021.03.11 |
---|---|
질의 문자열, GET과 POST 방식의 차이 (0) | 2021.03.11 |
Servlet 응답 정보 처리 (HttpServletResponse, 한글 응답) (0) | 2021.03.11 |
서블릿 구현 및 실행 (web.xml, @WebServlet 설정) (3) | 2021.03.11 |
Servlet 객체의 상속 구조, Servlet 객체 생명 주기 (0) | 2021.03.10 |
댓글