월요일, 12월 23
Shadow

#024 요청과 응답

01. 서블릿이 되어 보자.

서블릿은 컨테이너가 관리합니다.
Request, Response 객체를 생성하고, 서블릿의 새로운 스레드를 만들어 서블릿 service() 메소드를 호출하고, Request와 Response 객체에 대한 참조를 인자로 넘긴다는 내용입니다.
1. 사용자가 서블릿에 대한 링크(URL)을 클릭합니다.
2. 컨테이너는 요청된 Request가 서블릿이라는 것을 간파하고는 다음 두개의 객체를 생성합니다.
1)HttpServletResponse
2)HttpServletRequest
3. 접수한 요청의 URL을 분석하여 어떤 서블릿을 요청했즌지 파악합니다. 그다음 해당 서블릿 스레드를 생성하여 Request, Response  객체참조를 넘깁니다.
4. 컨테이너는 서블릿 Service() 메소드를 호출합니다. 브라우저에서 지정한 방식에 따라 doget()을 호출할지 doPost()를 호출할지 결정합니다.
클라이언트가 HTTP GET 메소드를 날렸다면, service()  메소드는 서블릿의 doGet(0 메소드를 호출합니다. 호출할때 Request와 Response객체를 인자로 넘깁니다.
5. 서블릿 클라이언트에게 응답을 작성하기 위하여 response 객체를 사용합니다. 이작업을 완료하면 Response에 대한 제어는 컨테이너에게 넘깁니다.
6. service() 메소드가 끝나면, 스레드를 소멸하거나 아니면 컨테이너가 관리하는 스레ㅐ드 풀로 돌려보냅니다. 그다음 Requset와 Response 객체는 가비지 컬렉션이 될 준비를 할 것이며, 이 객체에 댛나 참조는 이제 범위를 벗어니가에 사라집니다. 마지막으로 클라이언트는 서버로 부터 응답을 받게 됩니다.

서블릿의 일생에는 아직 더 많은 것들이 있습니다.
1. 클래스로딩
2. 서블릿 인스턴스화(생성자 실행)
3. init()
4. service() – 초기화
5. destory() – 초기화

서블릿 일생에 있어서 3번의 중요한 순간들
1. init
호출되는 시점 : 컨테이너는 서블릿 인스턴스를 생성한 다음 init()메소드를 호출합니다. 이메소드는 service()메소드 전에 실행되어야 합니다.
목적 : 클라이언트의 요청을 처리학 전에는 서블릿을 초기화 할수 있는 것입니다.

2. service()
호출되는 시점 : 최초 클라이언트의 요청을 받았을떄, 컨테이너는 새로운 스레드를 생성하거나, 이니면, 스레드 풀로 부터 하나를 가지고 와서 서블릿의 service(I) 메소드를 호출합니다.
목적 : 클라이언트의 HTTP 메소드를 참조하여 ,doGet() 을 호출할지, doPost()를 호출할지, 아니면 다른 메소드를 호출할지를 판단합니다.

3. doGet/doPost
호출되는 시점 : service() 메소드가 클라이언트의  HTTP 메소드를 참조하여 ,doGet() 을 호출할지, doPost()를 호출할지, 아니면 다른 메소드를 호출할지를 판단합니다.
목적 : 여기에다가 코딩하면 됩니다. 어떤 웹 애플리케이션이든지, 무서을 하든지 관계없이 이곳이 바로 그 작업을 하는 곳입니다. 물론 다른 객체에 있는 달느 메소드를 호출할수 있습니다. 하지만 모두 여기에서 부터 시작합니다.

서블릿이 되어보자에서 무엇을 배웠습니까?
1. ServletConfig 객체
서블릿당 ServletConfig 겍체 하나
서블릿 배포시 설정된 정보를 서블릿으로 넘겨주기 위하여
ServletContext에 접근하기 위해서 이 객체를 사용
파라미터값은 배포 서술자에서 설정 가능

2. ServletContext 객체
웹 애플리케이션 당 하나의 ServletContext
웹애플리케이션의 파라마터 정보를 읽어오기 위하여 사용합니다.
이것은 일조으이 애플리케이션용 게시판 같은 것이니다. 여기에다가 메시지를 적어 놓으면 애플리케이션의 다른 녀석들이 이를 읽을수 있습니다.
서버정보를 파악하기 위하여 사용합니다. 컨테이너의 이름 및 버전, 지원하는 API버전등

그러나 서블릿 본연의 임무는 요청을 핸들링 하는 것입니다. 여기에 서블릿 삶의 의의가 있지요

HTTP 요청 메소드는 doGet(을 실행할지 doPost()를 실행할지 결정합니다.
클라이언트의 요청에는 HTTP 메소드가 무엇인지에 대한 정보가 들어있습니다. HTTP 메소드가 GET이라면 service()는 doGet()을 호출할 것이며, POST라면 doPost()를 호출합니다.

정리 :
GET : URL로 자원 또는 파일을 달라고 요청함
POST : Request에 첨부한 몸체 정보를 서버로 보내어, 요청한 URL로 이 정보를 넘겨주라고 요청함. 뚱뚱한 GET이라고 부를수 있음. 부가 정보를 가진 GET
HEAD : GET이 무엇을 리턴하든간에 헤더정보만 요청함 이는 Response의 몸체 정보가 없다는 것만 빼면 Get과 동일함. 요청한 URL로 부터 요청한 정보는 빼고 헤더 정보만 가지고 오는것임
TRACE :  요청한 메시지의 루프백 테스트를 요청함. 서버쪽에서 무엇을 받았는지를 알고 싶을때 하는 테스트, 테스트 목적 또는 문제해결을 사용함.
PUT : 동봉한 몸체 정보를 요청한 URL로 올리기 위해 사용함.
DELETE : 요청한 URL에 있는 자원이나 파일을 삭제하기 위해 사용함
OPTIONS : 요청한 URL이 응답할수 있는 HTTP메소드가 무엇인지 요청함
CONNECT 터널링의 목적으로 연결을 요청함

GET과 POST의 차이점
POST는 몸체가 있다. 이것이 핵심입니다. GET과 POST는 둘다 파라미터를 보낼수 있습니다. 그러나 GET은 주소 줄에다가 보내야 하기 때문에 보낼수 있는 파라미터 데이터의 양이 제한되어 있습니다.

POST는 멱등이 아닙니다.
HTTP GET은 말 그대로 무엇인가를 서버로 가져오는것이지 서버에 수정을 가하는것이 이닙니다. GET은 HTTP 스펙에 따르면 멱등 메소드 입니다. GET은 어떤 부작용을 없이 여러번 실행할수 있습니다.
POST는 반다로 멱등 메소드가 아닙니다. POST로 전송되는 몸체의 정보는 트랜잭션을 위한 것이면, 이는 되돌릴수 있는 성질의 것이 아닙니다. 이런 이유 때문에 doPos()를 할때 유의해야 합니다.

파라미터 1개 전송 및 사용하기
HTML 폼
<form method=”POST” action=”SelectBeer.do”>
<select name = “color”size=”1″>
<option> light
<option> dark
</select>
<input type=”submit”>

서블릿 클래스
public vodid doPost(HttpServletrequest request, HttpServletResponse response) throws IOException, ServletException{
String colorParam = request.getparameter(“color”);
}

파라미터 하나가 여러개의 값을 가질수 있습니다. 이 값을 읽으려면 getparameter()로 string을 리턴받으면 안되고 getparameterValue()메소드를 사용하여 배을을 리턴받아야 합니다.
String on = request.getParameterValues(“sizes”)[0];
String[] sizes=request.getparameerValues(“sizes”);
for(int x=0; x<sies.length; x++){
out.println(“<br>size: ” + sizes[x]);
}

파라미터 말고 request 객체에서 얻을수 있는 정보는 어떤것이 있죠?
1. 클라이언트 플랫폼 정보 및 브라우저 정보
String client = request.getHeader(“User-agent”);
2. Request에 관련된 쿠키
Cookie[] cookies = request.getCookies();
3. 클라이언트의 세션 정보
HttpSession session = request.getSession();
4. Request의 HTTP 메소드
String theMethod = request.getMethod()
5. Request의 입력 스트림
InputStream input = request.getInputStream();

—————————————————————–리뷰 : 서블릿의 생명주기와 API
컨테이너는 서블릿을 로딩합니다. 그 다음 디폴트 생성자를 호출하고 init() 메소드를 실행합니다.

ㅇ init() 메소드는 서블릿의 일생중 단 한번만 호출합니다. 이호출도 클라이언트에게 서비스를 제공하기 전에 실행됩니다.
ㅇ init()메소드에서 servletConfig 객체와 ServletContext 겍체에 접근할 수 있습니다. 이 두객체를 통해 서블릿 및 웹 애플리케이션 설정 정보를 파악할수 있습니다.
ㅇ 컨테이너는 서블릿의 destroy() 메소드를 호출하여 서블릿 일생을 마감합니다.
ㅇ 서블릿은 일생의 대부분을 클라이언트 요청에 대한 응답으로 service() 메소드를 실행하는데 보냅니다.
ㅇ 서블릿에 대한 클라이언트 요청은 별개의 스레드에서 실행됩니다. 서블릿 인스턴스는 하나 밖에 없습니다.
ㅇ 서블릿 작성 javax.servlet.http.HttpServlet을 상속받는 것에서 부터 출발합니다. HttpServletRequest와 HttpServletResponse를 인자로 하는 HttpServlet의 service() 메소드를 그대로 상속 받아 사용합니다.
ㅇ HttpServlet은 대부분 기본적인 서블릿 메소드가 이미 구현된 추상 클래스인 javax.servlet.GenericServlet을 상속 받습니다.
ㅇ GenericServlet은 Servlet 인터페이스를 구현한 것입니다.
ㅇ 서블릿 클래스들은 모두 javax.servlet과 javax.servlet.http 두 패키지에 속합니다.
ㅇ init() 메소드를 재정의 하는 것도 가능합니다. 그러나 doGet()과 doPost()중 하나는 반드시 재정의해야 합니다.

—————————————————————–리뷰 : HTTP와 HttpservletRequest
ㅇ HttpServlet의 doGet()메소드는 HttpServletRequest와 HttpServletResponse를 인자로 합니다.
ㅇ Service()메소드는 HTTP Request의 HTTP 메소드에 따라 doGet()을 호출할지 아니면 doPost()를 호출할지 결정합니다.
ㅇ POST요청에는 몸체가 있습니다. Get 요청에는 몸체가 없습니다. Get파라미미터는 URL의 실제 주소 뒤에 연결됩니다. 보통 이를 쿼리 스트링이라고 부릅니다.
ㅇ GET요청은 HTTP 스펙 1.1에 따르면 멱등 메소드 입니다. 이말은 서버에 부작용을 일으키지 않고는 여러번 실행 가능하다는 말입니다. GET 요청은 서버에 수정을 가하는 것이 아닙니다. 그러나 의도적으로 멱등이 아닌 doGet() 메소드를 작성할수는 있습니다.
ㅇ HTML 폼에 “method=POST”를 코딩하지 않았다면 이 요청은 POST가 아니라 GET 입니다. 이경우 서블릿에 doGet()이 없다면 오류가 납니다.
ㅇ Request 객체에서 파라미터를 뽑아내기 위하여 getparameter(“파라미터 이름”) 를 호출합니다. 리턴되는 겂은 언제나 Stirng 입니다.
ㅇ 그러나 파라미터값이 여럿인 경우 getParameterValues(“파라미터 이름”)메소드를 사용합니다. 리턴되는 값은 String 배열입니다.
ㅇ 이외에 Request 객체에서 헤더 정보, 쿠키정보, 세션정보, 쿼리 스티링, 입력 스티림관련 메소드를 사용하룻 있습니다.

지금까지 Request였고 이제 Response에 대해 알아보죠
Response는 클라이언트로 돌려보낼놈 입니다. 이 정보를 분석해서 브라우저는 화면을 출력합니다. 일반적으로 Response객체의 출력 스트림을 사용하여 HTML을 작성합니다. Response객체에는 I/O출력 이외에 다른 메소드들도 있는데 여기 대해서 조금뒤 자세히 알아보죠.

클라이언트에 JAR 파이을 전송한다면….
1. 다이아나는 지금 배우고 있는 서블릿/jsp 책의 예저 소스 코드인 jar 파일을 내려 받기 위해 웹 사이트를 이리저리 기웃거리고 있습니다. 결국 추판사 웹사이트에서 code jar라는 링크를 반견하고는 이를 클릭합니다. 쿨릭하고 보니 code.do 라는 서블릿을 실행하는 것이었습니다.
브라우저는 code.do라는 이름의 서블릿에 대한 HTTP 요청을 서버로 날립니다.
컨테이너는 dd를 뒤져보니 code.do 가 CodeReutrn이라는 이름을 가진 서블릿에 매핑되어있는 것을 확인하고는 이 서블릿에게 처리를 요청합니다.

2. CodeReturn 서블릿은 jar 바이트를 읽어와서 이를 response의 출력스트림에다가 쓰기 작업을 하니다.
HTTP Response 에는 이제 jar 바이트가 들어있습니다.
다이아나는 PC로 jar 파일을 내려 받고 있습니다.

jar를 내려 받는 서블릿 코드

public class Codereturn extends HttpServlet{
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{
response.setContentType(“application/jar”);

servletContext ctx = getServletConxt();
InputStream is = ctx.getResourceAsStream(“/bookCode.jar”);

int read = 0;
byte[] bytes=new byte[1024];

OutputStream os = response.getOutputStream();
while((read = is.read(bytes)) != -1){
os.write(bytes, 0, read);
}
os.flush();
os.close();
}

가끔 서블릿에서 응답하지 않을수 있습니다.
리다이렉트
1. 브라우저 주소 창에 URL을 입력합니다.
2. 서버/컨테이너로 요청이 날아갑니다.
3. 서블릿은 요청을 다른 URL로 보내야 하는 것임을 간파한 다음
4. Response 객체의 sendRedirect() 메소드를 호출합니다. 이것으로 서브릿임무는 끝
5. HTTP Response에는 상태 코드 헤더에 301값과 Location 헤더에 새로운 URL 값을 포함하고 잇습니다.
6. 브라우저는 응답을 받은 다음, 상태코드가 301을 확인한다음 Location 헤더값이 무엇인지를 확인합니다.
7. Location값으로 받은 URL로 부라우저는 새로운 요청을 날립니다. 사용자도 부라우저의 주소창의 값이 바뀌는 것이 보이기 때무에 이 사실을 알수 있습니다.
8. 사실 새로 발생한 요청이 처음 요청과 비교해 다른점은 없습니다. 단지 방향 바꾸기에 의한 생성된 요청이라는 것만 빼면,
9. 서버는 요청을 접수합니다. 여기에도 뭐 별 특별한것은 없습니다.
10. 다른 HTTP Response와 별반 다른 것이 없는 응답을 보냅니다. URL  자체가 사용자가 입력한 값이 아니라는것만 빼고는
11. 브라우저는 리턴 받은 내용을 화면에 출력합니다. 놀라운 사용자 얼굴이 보입니까?

서블릿 리다이렉트는 브라우적 이 작업을 합니다.

if(worksFrome)
}else{
response.sendredirect(http://www.starstory.us);

요청 디스패치는 서버에서 일어나는 일입니다.
리다이레트와 요청 디스패치는 다음과 같은 차이가 있습니다. 리다이렉트는 작업이 클라이언트에서 일어나지만, 요청 디스패치는 서버상에서 작업이 일어난다는것입니다.

요청 디스패치
1. 브라우저 주소창에 서블릿URL을 입력합니다.
2. 서버 컨테이너로 요청이 날아갑니다.
3. 서블릿이 보기에 이 요청은 웹 애플리케이션의 다른 컴퓨넌트가 처리해야 된다고 판닪나다음
4. 서블릿은 다음 코드를 실행합니다.
RequestDispatcher view= request.getRequestDispatcher(“result.jsp”);
view.forward(request, response);
이제 제어는 JSP에게 넘어 갔습니다.
5. 여느때와 마찬가지로 브라우저는 응답을 받고 화면에 출력합니다. 이다이렉트처럼 브라우저주소창의 값이 바뀌지 않습니다. 브라우저는 JSP가 페이지를 만들었는지, 서블릿이 만들었는지 알길이 없죠.

—————————————————————–리뷰 : HttpservletResponse
ㅇ 클라이언트로 데이터를 보내기 위한 Response 객체를 사용합니다.
ㅇ Response 객체에서 가장 많이 사용하는 메소드는 setContentType()과 getWriter()입니다.
ㅇ 많은 개발자들이 착각하고 있는 것 하나. GetPrintWriter()라고 생각하는데 getWriter()가 맞습니다.
ㅇ getWirter() 메소드를 가지고 HTML을 작성하는 것과 같은 문자 I/O 작업을 합니다.
ㅇ Response 객체를 가지고 헤더를 설정하고 오류를 전송하며 쿠키도 추가할수 있습니다.
ㅇ 실제 프로젝트에서는 HTML 응답을 보내기 위하여 JSP를 사용합니다. 그럼에도 불구하고 JAR 파일 같은 바이너리를 전송하기 위하여 Resposne 스트림을 사용합니다.
ㅇ Response에서바이너리 스티름을 리턴받은 메소드는 getoutputstream 입니다.
ㅇ 브라우저가 응답으로 들어오는 데이터를 어떻게 핸들링 할지 알려주는 메소드는 setcontentType() 입니다. 일반적인 컨텐츠 타입은 text/html, application/pdf, image/jpeg등이 있습니다.
ㅇ MIME으로 알려져 있는 컨텐츠 타입을 외울 필요는 없습니다.
ㅇ 헤더는 addHeader() 나 setHeader()를 가지고 값을 설정합니다. 두개의 차이는 헤더가 이미 존해하는냐 아니냐에 따라 다르게 해동하는것입니다. 헤더가 존재하는 경우, setHeader() 값을 새로운 값으로 데체하고, addHeader()는 값을 하나 더 추가합니다. 헤더가 존재하지 않는 경우에는 setheader()와 addHeader()는 똑같이 헤더와 헤더값을 response에 추가합니다.
ㅇ 요청에 응답하지 않고, 요청을 다른 URL로 리다이렉트 할수 있습니다. 이경우 브라우저는 서버에서 정한 URL을 받아 새로운 요청을 보냅니다.
ㅇ 리다이렉트 하기 위해서는 Response의 sendredirect(aString URL) 메소드를 호출합니다.
ㅇ Response에 적압을 하고는 sendredirect()를 호출할수는 없습니다. 즉, 스트림에 쓰기 작업을 이미 했다면, 리다이텍트 하기엔 너무 늦었다고 해야 할까요?
ㅇ 리다이렉트와 디스패치는 다릅니다. 요청을 디스패치하는것은 서버에서 일어나고, 리다이렉트하는것은 클라이언트에서 일어납니다. 디스패치 작업은 서버 상에 있는 다른 컴포넌트로 작업을 넘기는 것이라면, 디다이렉트는 완전히 다른 URL로 가라고 브라우저에게 지시하는 것입니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

이 사이트는 스팸을 줄이는 아키스밋을 사용합니다. 댓글이 어떻게 처리되는지 알아보십시오.