Cache Control
- 세가지의 속성들을 모두 사용하여 웹접근성 보장
- 어느 브라우저에서도 캐시컨트롤이 될 수 있도록
Pragma
Cache-Control
Expires
- 캐시 만료시간 셋팅
- setMaxAge vs. Expires
- setMaxAge: 기간
- Expires: 시점
refresh
- 서버사이드에서 주기적으로 갱신되는 데이터들을 어떻게 클라이언트가 쉽게 가져갈 것인가
동기
- 동기방식으로 적용
- 전체 윈도우 대상으로 refresh
비동기
- 화면 전체에 락을 걸지 않고 (=ui는 리프레시하지않고) 데이터만 리프레시해서 가져오는 방법
- 주기적으로 비동기요청을 발생시키려면 long polling 방식이 필요
- Long Polling
- long polling으로 주기설정하려면 js의 스케줄링 함수 필요
- setTimeout: 시간지연
- setInterval: 주기적인 작업 (+ clearInterval)
- long poliing방식의 단점
- 1) 완전한 실시간이 아님 (마치 실시간인 것처럼 과장)
- setInterval의 주기1초
- 1초와 1초사이 그중간에 0.5초사이에 갱신데이터 실시간으로 가져갈수있어? -> 못함
- 2) 빠른 주기의 요청으로 인한 서버의 부하
- 서버 입장: 불특정 다수의 클라이언트가 매 1초마다 요청
- longpollling 단점 해결
- 1) 웹소켓
- 2) server-sent event
- ajax와 fetch의 공통점, 차이점
- 공통점: ajax나 fetch나 setInterval없으면 소용x => long polling 방식이란 증거
- 차이점: 비동기 요청을 어떤 식으로 발생시킬 것인가?
- 사용하는 api는 다르지만, 기본적으로 락을 걸지않고 비동기요청을 발생시킨다는 사실은 같음
- ajax: XMLHttpRequest
- fetch: promise객체를 이용해 promise pattern을 이용
Ajax
$.ajax({
url : "getServerTime.jsp",
method : "get",
dataType : "text",
error : function(xhr) {
console.log(xhr);
}).done(function(xhr) {
timeArea.text(resp);
}
});
- 기본적인 사항
- 응답데이터의 사이즈가 크다면 네트워크에서 처리할 수있는 단위의 청크로 끊어져서 옴
- success
- 모든 청크가 다 들어와서 완전한 형태의 응답데이터가 만들어지고 그 응답데이터에 대해 언마셜링까지 끝나고 나서야 호출
- done
- 요청에 대한 처리가 다 끝나면(= 응답데이터가 완전히 다 도착을 하고 나면) 호출
- done을 넣었다는 것은 success 펑션을 넣은 것과 비슷
- done과 success 차이점
- success: 콕 찝어 성공했을때만
- done: 성공 실패, 모든 상황을 커버함 (promise 객체처럼)
- 마치 fetch처럼 사용하기 위해 ajax에서 이 방식을 사용
Fetch
- 함수 자체를 호출할 때는 많은 정보를 넘기지않지만 비동기 요청 이후의 상황을 promise객체의 상태로 넘겨줌
- promise를 받은 이후에 취할 액션을
then과 fetch로 설정
- promise를 쓰냐 안쓰냐의 차이가 xhr과 fetch의 차이
- 간혹 필드에서는 ajax에서 fetch방식을 사용하기도함
Server-Sent Event (SSE)
- server-sent
- Event Source로 단 1번의 요청을 넘김(인터벌로 묶여놓지않기때문) -> 한번의 요청으로 인해 연결이 수립된 이후 건건의 데이터(메시지 이벤트)가 그 통로로 계속 전달이 되어 클라이언트사이드에서 처리됨
- connectless 방식이 아니다
- text 형식의 stream data가 흘러와야한다
- interval이나 timeout으로 묶여있지않음
- getservertime sse.jsp
- mime: text/event-stream; : 흐름으로 전달이되어야한다
- 데이터가 흐름으로 전달될때 문제점?
- 경계가 어디냐? 경계모호해짐
- 데이터가 건 by 건으로 전송되어야하는데 한 건과 다른 건의 이벤트를 어떻게 식별할거냐? -> enter 2번
- 건 별 데이터를 처리하기 위해 eventlistenr를 사용하고있음
- 데이터타입을 test로 했기떄문 이벤트의 타입이 test인것
- 이벤트소스에서는 하나의 어플리케이션을 구성할때 Event-driven 방식으로 구성할 수 있다
- SSE 장점
- 한 번의 요청으로 연결통로를 수립한 후, 여러번의 요청을 보내지 않고도 통로를 재활용하여 사용 가능
- 서버사이드에서 클라이언트쪽으로 푸시메세지를 보낼때 (섭->클의 일방적구조) 적합
- SSE 단점
- 클->섭으로의 데이터 전달 불가능
- 양방향 실시간 통신이 필요하다면 웹소켓을 사용해야함
흐름제어
dispatch (forward, include)
- 공통점: 둘다 RequestDispatcher(분기제어 관리자)를 이용해서 서버내에서 이동하는 구조
- 서버내에서만 이동: 중간에 응답데이터가 나가지않는다
- a -> b로갈때 a에게 발생한 요청정보가 사라지지않는다
- 분기라고 표현하는 이유: 출발점에서 발생한 데이터를 도착지까지 그대로 가져가기때문
- state가 그대로 유지가된다
- dispatch 주로 쓰이는 상황
- 1) 모델2구조 (forward)
- 컨트롤러에서 모델데이터가 만들어지고 뷰단으로 넘겨야할때 이때 forward를 주로사용
- 2) validation하다가 문제가 생겼을 때 (forward)
- 요청이 완전히 처리되지 않았는데 request를 없애버리면안되니까 request살리기위해 dispatch 방식이용
- 3) 페이지모듈화 (include)
- 하나의 응답데이터를 보낼 떄 여러 개의 JSP로 페이지만들떄 쓰는 방식
forward
- 최종 응답데이터는 a -> b로 갔다면 b에서 최종 응답데이터가 나감
include
- a -> b로 간후 b에서 데이터 처리후 a로 돌아감
- a에서 만들어졌던 데이터 + b에서 만들어졌던 데이터가 모두 합쳐져서 응답데이터가 나감
- b를 include한다
- 출발지와 도착지에서 만들어진 모든 UI가 전송되는 구조
redirect
- 최초 요청 발생
- 최초 요청에 대한 처리가 이루어짐
- 바디가 없고, 302/307이라는 상태코드와 로케이션, 함께 내보냄
- 브라우저가 300번대 상태코드를 보고 헤더를 뒤져 로케이션을 찾아냄
- 로케이션에 있는 주소(클라이언트사이드 주소)로 브라우저가 새로운 요청을 보냄
- 최종 응답은 마지막으로 이동한 최종 도착지인 B에서 완전한 UI가 나가게됨
- 클라이언트는 도착지 B에 대한 정보를 안다
- 브라우저가 새로운요청을 보냈기때문에 알고있음
- 하지만 디스패치방식에서는 서버 안에서만 이동 했기때문에 클라이언트는 B의 정보를 모른다
- 디스패치 방식에서는 클라잉언트가 모든 응답이 A에서 왔다고 착각
- 클라이언트가 이 상태에서 F5키를 눌럿을떄 다시 A에 대한 요청이 발생함
- 리다이렉트방식으로 F5를 누르면 이번엔 B로 요청발생
redirect vs. forward예시
예시1: 로그인 후 페이지 이동 (redirect)
- 네이버에서 비로그인상태로 검색 이용
- 상단 메일 버튼 누름
- 로그인 페이지로 연결됨
- ID/PW 입력
- 로그인버튼누름
- 메일 페이지로 넘어감
- 메일 페이지에서 F5 -> 메일페이지가 나와야함
- 로그인에서 성공하고 메일페이지로 가는 방식 -> 리다이렉트
- 로그인 성공 후 리다이렉트로 응답데이터가 하나 전송
- 그 응답데이터 헤더의 로케이션에 메일 페이지 주소를 심어져있음
- 그럼 브라우저에서 헤더에 있는 메일 페이지로 새로운 요청을 보냄
- 브라우저 주소는 메일 페이지가 남아있겠지 -> 그럼 역시 새로고침해도 메일페이지
- 만약 디스패치방식으로 갔다면?
- 클라이언트의 주소에는 여전히 로그인을 하기위해 사용했던 주소가 남아있음 - 메일페이지가 뜨기는 떴더라도 새로고침을 하더라도 로그인 페이지가 나오게됨
예시2: 회원 가입 (redirect)
- 가입 버튼 클릭
- 가입 양식 출력
- 가입에 필요한 정보 입력 후 가입하기 버튼 클릭
- 모든 정보가 서버쪽으로 전송
- 서버에서는 DB에 저장해서 회원으로 만듬
- 이 순간 가입하겠다는 명령에 대한 처리는 전부 끝남
- 그럼 request에 들어있던 개인정보는 남아있을 필요없음
- 최종적으로 가입에 성공했다면 클라이언트에게 로그인 페이지를 줘야함
- 가입이 완전히 끝남 = 가입하기위해 가지고 있던 정보는 없애도 됨
- 그걸 없애고 최종적으로 로그인 페이지로 가기위해서 리다이렉트로 가야함
예시3: 가입에 실패할 경우 (forward)
- 가입 양식 전송함
- 하지만 서버에서 확인해보니 중복아이디 -> 가입불가한 상황
- 다시 가입FORM 페이지
- 아이디만 중복이된거지 나머지 데이터는 전부정상
- 나머지 데이터는 다시 입력해야할 필요없음
- 가입하다가 실패했을때는 가입양식으로 다시보내야한다 -> FORWARD
- 아직 가입처리가 완료가 되지않았다 == RQUEST를 아직 다 못써먹었다 == REQUEST에는 아직 가입을 위한 데이터들이 남아있고 가입이 아직 안끝났으니까 살려둬야함
- 이래야 클라이언트가 귀찮게 또 입력안하지
CalculateServlet
if(MimeType.HTML == mime) {
String view = "/WEB-INF/views/calculate.jsp";
req.getRequestDispatcher(view).forward(req, resp);
}
모델2: 요청은 서블릿, 응답은 jsp가 처리
- jsp: 요청을 직접적으로 받을 필요 없기 때문에 주로 /WEB-INF/ 밑에 위치
- 서블릿: /WEB-INF 밖에 있으면서 웹에서 요청을 받을수 있음, 명령에 대한 처리 후 모델 데이터를 만듬, 그 모델데이터를 jsp에 넘겨줘야함,
- 서블릿->jsp(/WEB-INF)로 가야하는 상황
- forward 사용 이유
- 모델2에서 뷰단으로 넘겨야하는 데이터를 request 스코프에 담아갈 수 있음
- redirect 사용 불가 이유
- /WEB-INF/views: 서버에서만 접근할 수 있는 경로
- /WEB-INF 밖이라 하더라도 응답 나가는 순간 요청데이터 사라지기때문에 사용할 수 없음
- 이때의 최소한의 스코프는 session
- inlcude 굳이 안쓰는 이유
- 되긴 되는데 쓸 이유가 없음
- 서블릿에서는 ui가 만들어지지 않기 때문에 다시 돌아올 필요가 없음
로그인 & 로그아웃
<form id="loginForm" action="<%=request.getContextPath() %>/login/loginProcess.do" method="POST">
- action을 번역하는 건 브라우저 -> 컨텍스트패스 필요(클라이언트사이드 경로)
- 보안이 필요한 요청 -> POST
- attr vs. prop
- attr: 문자열로 관리하는 속성에 접근
- prop: boolean값 속성
LoginProcessServlet.java
LogoutServlet.java
HttpSession session = req.getSession();
session.removeAttribute("authMember");
- 로그아웃 상태로 바뀌는 게 아닌 로그아웃상태가 된 것 처럼 보이는 것일 뿐
- 만약에 로그인 후, 세션 스코프에 필요한 데이터를 넣어두었다면 로그아웃 시에 그 데이터를 전부 remove 하고 authmember 를 지운 후 세션을 만료 시켰어야함
session.invalidate();
(세션 만료시키기)
- 세션 스코프 안 모든 attribute를 하나 하나 다 지워준 후 현재 세션을 만료시킴
- 만료시키면서 각 세션을 식별하는 세션 id도 없애줌
index.jsp
- a 태그를 통해서 post 방식으로 요청 발생시키기
function clickHandler(event){
event.preventDefault();
let href = event.target.dataset["href"];
let logoutForm = document.logoutForm;
logoutForm.action = href;
logoutForm.submit();
return false;
}
<form name="logoutForm" method="post"></form>
<a onclick="clickHandler(event)"
data-href="<%=request.getContextPath()%>/login/logout.do"
href="#"> 로그아웃</a>
코드 유의사항
validation 시점 = 전송 하기 전!
- 1) 데이터 입력시
- 2) 정말로 전송하기 바로직전
- form 태그 대상으로 validation 수행
1. 클라이언트 사이드 검증
2. 서버 사이드 검증
- null 체크 및 validation 체크 따로 해줘야함
과제
- 서버사이드 validation
- python regex