전통적인 서버 클라이언트 구조
특징
서버에서 데이터를 처리 -> 자료 중복 및 자료 불일치 문제 해결
문제점
애플리케이션 서버 도입
특징
비즈니스 로직을 전문으로 처리하는 서버를 둠 -> 애플리케이션서버
클라이언트 실행 결과 출력만을 담당 -> 씬 클라이언트(thin client)가능
애플리케이션 서버에서 DBMS 접근 -> 보안 강화
기능 추가 또는 변경 시에 서버쪽만 변경 -> 배포가 쉬움
서버에서 데이터를 처리하고 비즈니스 로직을 처리하고 UI를 생성
특징 * 웹 표준 기술을 활용하여 클라이언트와 서버간 통신
웹 애플리케이션 구조
기존에 Socket프로그래밍, thread프로그래밍에서 진행하는 일을 웹서버가 대신 처리해주고 웹 어플리케이션은 계산기 프로그램을 예로들때 계산만 진행하는 역할을 한다. 대신 http프로토콜이 해석할 수 있도록 값을 전달해야한다.
직접 생성 html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>계산기</h1>
<form action="calc" method="post">
<input type="text" name="v1" style="width: 50px;">
<select name="op">
<option value="+">+</option>
<option value="-">-</option>
<option value="*">*</option>
<option value="/">/</option>
<option value="%">%</option>
</select>
<input type="text" name="v2" style="width: 50px;">
<input type="submit" value="=">
</form>
</body>
</html>
Servlet
package lesson01.servlets;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
@WebServlet("/calc")
@SuppressWarnings("serial")
public class CalculatorServlet extends GenericServlet {
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
String operator = request.getParameter("op");
int v1 = Integer.parseInt(request.getParameter("v1"));
int v2 = Integer.parseInt(request.getParameter("v2"));
int result = 0;
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
switch (operator) {
case "+":
result = v1 + v2;
break;
case "-":
result = v1 - v2;
break;
case "*":
result = v1 * v2;
break;
case "/":
if (v2 == 0) {
out.println("0 으로 나눌 수 없습니다!");
return;
}
result = v1 / v2;
break;
case "%":
result = v1 % v2;
break;
}
out.println(v1 + " " + operator + " " + v2 + " = " + result);
}
}
위처럼 서버에 애플리케이션 배포 및 실행하기에 기능변경 및 추가가 용이합니다.
웹애플리케이션 서버는 클라이언트로 부터 요청을 받으면 업무 로직에 따라 DBMS서버를 사용하여 데이터를 처러, 클라이언트의 접근을 제어하며 무효한 접근을 차단, 함께처리할 작업이 있으면 트렌젝션* 으로 묶어서 처리함
HTTP 프로토콜의 이해
HTTP는 무엇이고 웹서버와 웹 브라우저가 어떤형식으로 데이터를 주고받을까?
HTTP프로토콜이란?
웹 브라우저와 웹서버 사이에 데이터를 주고받는 규칙, 웹 브라우저에 통신에 따라서 웹서버가 응답을 해줌
데이터의 방식
웹 브라우저와 웹서버가 사용하는 통신의 종류
둘사이에 통신을 감시하는 모니터링 프로그램을 HTTP프록시라고 합니다.
HTTP프록시를 사용하여 둘사이 주고 받는 데이터를 직접 알아보기.
proxy를 두는이유 - 클라이언트와 서버사이에 통신을 중계해주는 프로그램을 말합니다. 빠른 전송을 위해 응답결과를 캐시에 저장해두고, 외부서버에서 데이터를 꺼내는 것이 아닌 캐시에서 바로 저장된 정보를 전달하기 떼문에 클라이언트는 빠른 응답을 받을 수 있습니다.
외부로 전달되는 데이터를 검사하여 특정 단어가 포함된 자료의 송수신을 차단할 수 있습니다.
www.charlesproxy.com을 사용하여 직접 설치
프록시를 사용하여 http프로토콜로 접근했을 때 서버의 요청 정보와 응답정보를 받을 수 있다.
자바프로그램을 이용해서 웹서버가 정말 응답을 하는지 알아보자
package lesson02.client;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
public class SimpleHttpClient {
public static void main(String[] args) throws Exception {
Socket socket = new Socket("www.hani.co.kr", 80);
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
PrintStream out = new PrintStream(
socket.getOutputStream());
//1. 요청라인
out.println("GET / HTTP/1.1");
//2. 헤더정보
out.println("Host: www.hani.co.kr");
out.println("User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0)"
+ " AppleWebKit/537.36 (KHTML, like Gecko)"
+ " Chrome/30.0.1599.101 Safari/537.36");
//3. 공백라인
out.println();
String line = null;
while((line = in.readLine()) != null) {
System.out.println(line);
}
in.close();
out.close();
socket.close();
}
}
웹서버에 기본 포트번호는 80이기 때문에 80포트번호를 적고, 주소를 적는다.
그리고 서버에게 수행할 작업을 알려주는 요청라인을 보냅니다. 요청형식은 get, 원하는 자원은 서버루트 폴더에 있는 기본문서 / 사용할 프로토콜은 http 버전은 1.1입니다.
이렇게 첫번 째 라인에서는 응답상태 정보 두번째라인부터 공백라인 전까지에 헤더등 공백라인 다음에는 html로된 본문데이터가 옵니다. 이렇게 통신규약에 맞추어 데이터를 보내고 받는다면 누구든지 해당 프로토콜의 클라이언트나 서버를 만들 수 있습니다. (반복문을 만들고 요청을 계속해서 보내는 것이 바로 d-doss공격 서버를 정신 못차리게 하는 것)
Get 요청
get요청으로 하면 parameter이름과 =값으로 나오게된다.
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Lesson 2 - GET 메서드</title>
</head>
<body>
<h3>GET 요청 1: 웹 브라우저의 주소창에 주소를 입력 후 실행할 때</h3>
<h3>GET 요청 2: 링크를 클릭할 때</h3>
<p>
<a href="http://www.google.com">구글</a><br>
<a href="http://www.facebook.com">페이스북</a><br>
</p>
<h3>GET 요청 3: 입력폼의 method 속성을 GET으로 지정했을 때</h3>
<form action="CalculatorServlet" method="get">
<input type="text" name="v1" size="4">
<select name="op">
<option value="+">+</option>
<option value="-">-</option>
<option value="*">*</option>
<option value="/">/</option>
</select>
<input type="text" name="v2" size="4">
<input type="submit" value="="><br>
</form>
</body>
</html>
method를 get요청으로 전달했을 때 http프로토콜에서 입력 창이 proxy를 통해서 나오는 것을 확인해 봤습니다. get요청의 특징은 다음과 같습니다.
검색할 때 검색결과를 알려줄 때 url을 보내주면 바로 상대방이 조회가 가능하다.
post요청
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>POST 요청</title>
</head>
<body>
<h3>POST 요청 1 - 로그인 폼</h3>
<p>
로그인 폼은 입력값 노출을 방지하기 위해 POST를 사용해야 한다.
</p>
<form action="LoginServlet" method="post">
아이디: <input type="text" name="id"><br>
암호: <input type="password" name="password"><br>
<input type="submit" value="로그인">
</form>
<h3>POST 요청 2 - 계산기</h3>
<p>
URL에 값이 포함되지 않아서 즐겨 찾기에 추가해도 소용없다.
</p>
<form action="CalculatorServlet" method="post">
<input type="text" name="v1" size="4">
<select name="op">
<option value="+">+</option>
<option value="-">-</option>
<option value="*">*</option>
<option value="/">/</option>
</select>
<input type="text" name="v2" size="4">
<input type="submit" value="="><br>
</form>
</body>
</html>
post로 지정을해서 프로토콜에서 데이터를 요청하게되면
url에 데이터를 실어서 보내는 것이 아니라 헤더 맨 끝에 데이터를 실어서 보내게됩니다. get방식은 서버에 요청할 때 주소에 데이터 정보가 포함되어있어 상대방에게 url을 전달했을 때 전달한 데이터 그대로의 웹정보가 나오게됩니다.
post 방식 대용량 데이터를 보낼 수 있습니다. (요청라인)url로 데이터를 보내는 것은 요청 정보의 양이 제한되어있지만, 한칸 띄고 보내는 post의데이터 방식은 대용량 데이터를 보내는 것이 가능합니다(메시지본문)라인에 데이터가 나오게됨(http)-프로토콜에 데이터 응답, 요청 방식.
중요.
get메서드와 마찬가지로 post도 데이터를 전달할 때 이름= 값 & 이름 =값 형태를 사용합니다 문자데이터를 보낼 떄는 문제없지만, 이미지나 동영상과 같은 데이터를 보낼 때는 문제가 발생할 수 있습니다. 바이너리 데이터 안에 =이나 & 같은 문자를 포함하고 있을 수 있기 때문입니다.
서버는 &문자로 매개변수를 구분하고 = 문자로 매개변수의 이름과 값을 분리하기 때문에, 만약 이미지데이터에 이런 문자 코드 값을 포함하고 있다면 잘못 해석될 수 있습니다.
파일 업로드
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>파일 업로드</title>
</head>
<body>
<h3>파일 업로드 POST 요청: Multipart 인코딩</h3>
<p>
입력폼의 method를 POST으로 지정하고,<br>
enctype 속성의 값을 multipart/form-data로 설정합니다.
</p>
<form action="FileUploadServlet" method="post"
enctype="multipart/form-data">
사진: <input type="file" name="photo"><br>
설명: <textarea name="description" cols="50" rows="3"></textarea><br>
<input type="submit" value="추가"><br>
</form>
</body>
</html>
보면 post타입은 맞는데 encodingType(enctype를) multipart/form-data형식으로 보냅니다.
확인해보면 form-data가 boundary 로 되어있는데 구분자를 ----기준으로 둔 것이고,
아래 확인해보면 form데이터의 이름과 파일 이름을 확인할 수 있습니다. 그아래에는 컨텐츠 타입을 알 수 있고, 한칸띄고 아래부분엔
파일의 데이터값을 확인 할 수 있습니다.
여기서 이해해야하는 부분은 get방식과 post방식은 http프로토콜로 서버에 보내고 받을 때 어떻게 다를까를 이해하는 것이 중요합니다.
정리하자면
get방식 = url(응답방식에)데이터가 포함되어 요청하고 전달받는다.(주로 검색에 사용)
post방식 = url에 데이터가 같이 나오지 않고, url데이터 요청(데이터 정보의 양이 작게 제한되어 있는 데 반해) 상대적으로 보낼 수 있는 데이터 용량이 커 많은 데이터를 전송할 수 있다. 헤더, 응답 데이터가 아닌, 한칸띄고 메시지 정보에 포함되어서 전송됨
파일형식은 서버에서 파일을 찾을 때 &와 =의 데이터 값이 포함될 수 있기때문에 enctype = "multipart/form-data" 형식으로 http프로토콜에 데이터를 전송해야 합니다. boundary로 경계를 구분짓고 여러개의 파일을 보내고, 마지막 boundary에 --가 있으면 파일 데이터의 끝 부분입니다.
ex)
출처
열혈강의 - 자바 웹 개발 워크북