<< 학습 목표 >>
1. XMLHttpRequest 객체를 사용해 요청을 보낼 수 있다.
2. MIME TYPE을 설명할 수 있다.
3. 동기(Synchronous)와 비동기(Asynchronous)에 대해 설명할 수 있다.
HTML 태그를 사용해서 서버로 요청을 하게 되면 페이지가 전환됨
마치 물건을 사기 위해 직접 매장에 가는 것
여기서는 페이지 전환 없이 서버로 요청하는 방법을 알아보자
페이지 전환 없이 서버로 요청하는건 물건을 인터넷으로 주문하는 것과 마찬가지
물건을 인터넷으로 주문하면 택배를 통해서 받는 것처럼
페이지 전환 없이 서버로 요청하기 위해서는 자바스크립트 또는 Jquery 를 사용해야함
우선 페이지가 전환된다는 사실을 다시 한번 확인해보자
https://codingaja.tistory.com/25 이 글에서 만들었던 회원가입 페에지를 사용해서 확인해보자
이처럼 적당히 데이터를 넣고 [ 회원가입 버튼 ] 을 눌러보자
잠깐! 여기서 주의 깊게 봐야할 건 페이지 URL
지금은 회원 가입 페이지에 있으니 당연히 회원 가입 페이지의 URL임
[ 회원가입 ] 버튼을 누르고 URL 을 확인해보자
이렇게 HTML만을 사용해서 서버로 요청을 하면 URL이 바뀜
지금처럼 요청했을 때 URL이 바뀌어도 되는 상황이 있지만 URL이 바뀌면 안되는 상황이 있음
URL이 바뀌어도 되는 상황에서는 HTML 로 요청을 보내고 URL이 바뀌면 안되는 상황이라면 JavaScript 또는 Jquery를 사용해 요청을 보내면 됨
JavaScript(자바스크립트 / 이하 JS 라고 하겠음 ) 를 사용해서 서버로 요청을 보내보자
JS를 사용해 서버로 요청을 보낼 때는 XMLHttpRequest 객체를 사용함
예시 코드를 보자
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if(this.readyState == this.DONE && this.status == 200) {
alert("서버가 처리 결과를 전달(Response) 함");
}
}
request.open("요청방식", "요청할 서블릿의 경로", true);
request.send();
이와 같이 JS의 XMLHttpRequest 객체를 사용해 서버로 요청을 보낼 수 있음
이 방식을 사용하면 페이지 전환 없이 그 페이지 그대로 있지만 요청을 하고 응답을 받을 수 있음
요청을 보낼 때 요청 방식은 request.open 메서드의 첫 번째 매개변수로 지정함
// GET 방식으로 요청
request.open("GET", "요청할 서블릿의 경로", true);
// POST 방식으로 요청
request.open("POST", "요청할 서블릿의 경로", true);
request.open 메서드의 세 번째 매개변수는 동기(Synchronous) 또는 비동기(Asynchronous) 방식으로 요청을 보내도록 조절하는 매개변수임
동기, 비동기는 약간의 설명이 필요하니 이 글의 마지막에 설명하겠음
서버가 응답했을 때 JS가 취할 행동은 function 안에 적어둠
request.onreadystatechange = function() {
if(this.readyState == this.DONE && this.status == 200) {
alert("서버가 처리 결과를 전달(Response) 함");
}
}
this.readyState == this.DONE 은 서버가 응답을 했다면 이라는 코드임
this.status 는 서버가 응답한 상태 코드를 뜻함
( 상태 코드에 대해 모르겠다면 https://codingaja.tistory.com/16 이 글을 보고 오자 )
if의 조건식을 해석해보면 아래와 같음
회원가입 페이지에 JS 를 붙여서 페이지 전환 없이 그 페이지 그대로 [ 회원가입 ] 요청을 보내자
아래 JS 코드를 </form> 과 </body> 사이에 넣자
<script>
let submitBtn = document.querySelector("input[type=submit]");
submitBtn.addEventListener("click", function() {
event.preventDefault();
let request = new XMLHttpRequest();
request.onreadystatechange = function() {
if(this.readyState == this.DONE && this.status == 200) {
alert("회원가입 완료!");
} else if(this.readyState == this.DONE && this.status == 400) {
alert("이미 사용중인 아이디입니다.");
} else if(this.readyState == this.DONE && this.status == 500) {
alert("서버에 문제가 생겼습니다.\n잠시후 다시 시도해주세요");
}
}
request.open("POST", "/studyProject/chapter03/join", true);
request.send();
});
</script>
이제 서버를 재시작하고 브라우저를 새로고침한 후에 [ 회원가입 ] 버튼을 눌러보자
페이지 전환 없이 현재 페이지 그대로인 상태에서 [ 회원가입 완료! ] 메세지가 뜸
이와 같이 페이지 전환 없이 요청을 보낼 수 있음
여기까지 다 배운것같지만 아직 한가지가 빠졌음
서버로 데이터를 담아 요청하기
서버로 데이터를 담아 요청할 때는 request.send 메서드의 인자로 데이터를 담으면 됨
그리고~! 내가 담은 데이터가 어떤 형태의 데이터인지 명시를 해줘야함
request.setReqestHeader("content-type", "내가 담은 데이터의 MIME TYPE");
request.send("데이터");
여기서 잠시 MIME TYPE 에 대해서 배우고 넘어가자
MIME TYPE 이란 내가 보내는 데이터의 형태를 뜻함
클라이언트가 서버로 MIME TYPE을 보내면 클라이언트가 서버로 보내는 데이터의 형태를 정의하는 것임
서버가 클라이언트로 MIME TYPE을 보내면 서버가 클라이언트에게 보내는 데이터의 형태를 정의하는 것
MIME TYPE은 여러가지가 있음
text/plain | text/html |
보내는 데이터가 아무 의미 없는 텍스트이다 | 보내는 데이터가 텍스트인데 HTML 코드로 이뤄진 텍스트이다. |
image/jpg | image/png |
보내는 데이터가 JPG 이미지 파일이다. | 보내는 데이터가 PNG 이미지 파일이다. |
application/json | application/x-www-form-urlencoded |
보내는 데이터가 JSON 이다. | 보내는 데이터가 form 태그 형식의 데이터다. |
form 태그는 GET, POST 다 데이터를 이름=값&이름=값&... 의 형태로 데이터를 보냄
XMLHttpRequest 객체를 사용해 form 태그 형식으로 데이터를 보낼 때는 다음과 같이 사용함
( request.open 이후의 코드 두 줄만 복사했음 )
request.setRequestHeader("content-type", "application/x-www-form-urlencoded; charset=UTF-8");
request.send("id=myId&pw=myPw&name=홍길동&gender=male&fav=exercise&fav=game");
여기까지 XMLHttpRequest 객체를 사용해 요청을 보내는 방법과 요청을 보낼 때 데이터를 담아 요청을 보내는 방법에 대해서 배웠음
이번에는 마지막으로 동기(Synchronous)와 비동기(Asynchronous) 용어를 배우고 마무리하자
동기란 순차적으로 일을 처리하는것을 뜻함
비동기란 비순차적으로 일을 처리하는것을 뜻함
동기의 예를 들어보자
아래와 같은 프로그램을 실행시킨다면 순차적으로 1, 2, 3, 4 가 출력될 것
아래 프로그램이 동기 방식
public class Ex01 {
public static void main(String[] args) {
System.out.println(1);
System.out.println(2);
System.out.println(3);
System.out.println(4);
}
}
비동기에 대한건 예를 들기 보다 직접 사용해보는게 나으니 비동기 예는 패쓰~!
동기, 비동기에 대해서 알아보기 위해 다음과 같은 서블릿 3개를 chapter03 패키지에 추가하자
package chapter03;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/chapter03/first")
public class First extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("First 서블릿 호출됨");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("First 서블릿 처리 완료");
}
}
package chapter03;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/chapter03/second")
public class Second extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Second 서블릿 호출됨");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Second 서블릿 처리 완료");
}
}
package chapter03;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/chapter03/third")
public class Third extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Third 서블릿 호출됨");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Third 서블릿 처리 완료");
}
}
위 세 서블릿은 요청이 들어왔을 때 5, 2, 1 초를 쉼
세 서블릿을 동기, 비동기 방식으로 요청하는 HTML 페이지를 만들자
webapp 안에 chapter03 안에 sync.html 을 만들고 아래 코드를 넣자
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>동기/비동기 테스트</title>
</head>
<body>
<button onclick="sync()">동기 방식으로 요청</button>
<button onclick="async()">비동기 방식으로 요청</button>
<script>
function sync() {
let req1 = new XMLHttpRequest();
let req2 = new XMLHttpRequest();
let req3 = new XMLHttpRequest();
req1.onreadystatechange = function() {
if(this.readyState == this.DONE && this.status == 200) {
console.log("req1 응답 받음");
}
}
req2.onreadystatechange = function() {
if(this.readyState == this.DONE && this.status == 200) {
console.log("req2 응답 받음");
}
}
req3.onreadystatechange = function() {
if(this.readyState == this.DONE && this.status == 200) {
console.log("req3 응답 받음");
}
}
req1.open("GET", "/studyProject/chapter03/first", false);
req2.open("GET", "/studyProject/chapter03/second", false);
req3.open("GET", "/studyProject/chapter03/third", false);
req1.send();
req2.send();
req3.send();
}
function async() {
let req1 = new XMLHttpRequest();
let req2 = new XMLHttpRequest();
let req3 = new XMLHttpRequest();
req1.onreadystatechange = function() {
if(this.readyState == this.DONE && this.status == 200) {
console.log("req1 응답 받음");
}
}
req2.onreadystatechange = function() {
if(this.readyState == this.DONE && this.status == 200) {
console.log("req2 응답 받음");
}
}
req3.onreadystatechange = function() {
if(this.readyState == this.DONE && this.status == 200) {
console.log("req3 응답 받음");
}
}
req1.open("GET", "/studyProject/chapter03/first", true);
req2.open("GET", "/studyProject/chapter03/second", true);
req3.open("GET", "/studyProject/chapter03/third", true);
req1.send();
req2.send();
req3.send();
}
</script>
</body>
</html>
[ 동기 방식으로 요청 ] 버튼을 누르면 JS의 sync 함수가 호출됨
1. sync 함수 안에서는 3개의 요청을 하기 위한 XMLHttpRequst 객체를 3개 생성했음
2. 각 객체가 요청을 하고 응답을 받았을 때 console 창에 "~~ 응답 받음" 을 출력하도록 함
3. 각 객체가 요청할 정보 지정 / 요청 방식(a), URL(b), 동기(c)
4. 요청
특히 마지막 요청을 보면 req1, req2, req3 순으로 요청했음
동기 방식이기 때문에 req1의 요청을 하고 서버가 응답을 해야 그 다음에 있는 req2.send() 코드가 실행됨
마찬가지로 req2의 요청에 대해 서버가 응답을 해야 그 다음에 있는 req3.send() 코드가 실행됨
[ 동기 방식으로 요청 ] 버튼을 누르고 브라우저의 개발자 모드 내 [ console ] 패널을 확인하자
이번에는 비동기 방식에 대해 알아보자
[ 비동기 방식으로 요청 ] 버튼을 누르면 async 함수가 호출되 동작하는데 동기 방식과 차이점은 3번의 c 밖에 없음
3번의 c가 false이면 동기 방식으로 요청을 하고 3번의 c가 true이면 비동기 방식으로 요청함
비동기 방식은 서버의 응답이 온 순서대로 처리함
비동기 방식의 요청은 req1.send() 로 요청을 보내고 응답이 올때까지 기다리지 않고 바로 다음 코드인 req2.send() 가 동작함 그래서 첫 번째 요청에 이어 두 번째 요청도 곧바로 들어감
마찬가지로 마지막 요청도 곧바로 들어감
첫 번째 서블릿은 5초를 기다리고 두 번째 서블릿은 2초를, 세 번째 서블릿은 1초를 기다리고 응답하므로 응답 속도가 제일 빠른 서블릿은 세 번째 서블릿 그 다음은 두 번째 서블릿, 마지막으로 첫 번째 서블릿임
따라서 [ 비동기 방식으로 요청 ] 버튼을 누르면 "req3 응답 받음", "req2 응답 받음", "req1 응답 받음" 순서대로 출력됨
동기, 비동기 또한 좋은 방식, 나쁜 방식이 아닌 상황에 맞는 방식이 있는것
그러나 대부분 비동기 방식으로 요청함
'Servlet + JSP > Serlvet-Chapter03' 카테고리의 다른 글
Chapter03. JSON 이란 (0) | 2023.03.02 |
---|---|
Chapter03. Jquery의 Ajax 로 요청하기 (0) | 2023.02.28 |
Chapter03. GET, POST 언제써야할까? (0) | 2023.02.28 |
Chapter03. 웹 페이지의 URL을 조금이라도 줄여보자 (0) | 2023.02.28 |
Chapter03. 클라이언트가 한글 데이터를 보냈다면? (0) | 2023.02.28 |