복습

HTTP

  • 비연결지향: 응답 데이터 나가면 연결 끝
    • 이제는 맞지 않는 말, 지금은 거의 CONNECTFULL로 동작
    • 연결 끊고 맺고하는게 낭비라 연결재활용하는 구조로 가고 있음

Response

Response Line

status code

  • 100: http 1.1에서 새로 나옴. Web Socket의 ing랑 같은 의미
  • 200: 성공
  • 300: 클라이언트의 추가 액션 요구 (성공도 실패도 아님)
    • 304(Not Modified): 정적 자원에 대한 응답데이터에서 사용됨
      • 브라우저가 정적자원을 캐싱한다는 것을 보여주는 단적인 예)
      • 네이버의 인덱스 페이지 하나가 동작하기위해 많은 자원이 필요하기때문에 매번 실시간으로 가져올 때 부하를 방지하기 위해 캐시에 정적 자원을 저장해둠.
        재방문시에는 HTML, CSS JS와 같은 정적 자원은 미리저장된 캐시에서 꺼내쓰라는 의미에서 304라는 상태코드로 회신하기때문에 로딩이 빨리됨.
        하지만 피씨 밀고 처음 열고 브라우저 켜서 네이버 들어가면 캐시없어서 로딩 오래걸림.

      • 오늘은 캐시로 304 제어하는 법 배울 것이다!
  • 400: 클라이언트 오류
    • 400: 클라이언트 요청 검증상황에서 주로 발생
    • 401/403: 보안
      • 주로 필터로 많이 사용됨(필터 목적: 기본 요청이 가지고 있는 걸 바꿔치기할때)
    • 404: 찾는 자원 서버에 없음
  • 500: 서버상 오류 (정보 노출때문에 세분화 시켜서 사용하지 않음)

protocol/version

Response Header

  • 메타데이터

Response Body




Request Header

Cache-Control

Refresh

Location


Cache-Control

  • cacheControl.jsp

사례 예시

  • 다음에 트래픽 속도가 엄청난 카페가 있다고하자, 9시에 접속했을때랑 퇴근시 접속했을때랑 1페이지가 같을까? 만약 그페이지가 캐싱을 저장한다면?
    • 맨처음 접속했을 때인 아침9시의 1페이지만 보일 거야
  • pc방에서 인터넷뱅킹으로 내계좌 거래내역을 조회했어 근데 그 거래내역페이지를 브라우저가 캐싱을 했다면?
    • 캐시는 브라우저에 파일처럼 저장됨 -> 누구나 볼 수 있게되는 것
  • jsp에서 새로고침하면 이미지가 200으로오는데 만약 이미지 주소로 요청을 새로하면 304로 옴
    • 304의 의미: 이미 당신의 브라우저 캐싱에 있어요 찾아보세요
    • 기타)
      • img src의 의미: src의 주소로 요청을 보내고 응답으로 바이너리데이터를 받아와 화면에 출력

헤더 예시

  • 웹표준화 전략에 의거, 웹접근성을 보장하려면 클라이언트가 사용하는 브라우저나 프로토콜 버전에 상관없이 모든 상황에서 응답을 보내야한다.
  • setHeader: 첫번째 설정시
  • addHeader: 두번째 설정에서 또 set을 쓰게되면 이전 거에 덮어씌워버림
  • 이걸 젤 쉽게하는 것이 .. 필터! 필터에서 정적자원 다 처리하고 넘기니깐.

Pragma(HTTP/1.0)

  • response.setHeader("Pragma", "no-cache");: 캐시를 남기지마
  • response.addHeader("Pragma", "no-store");: 저장하지마

Cache-Control(HTTP/1.1)

  • response.setHeader("Cache-Control", "no-cache");: 캐시를 남기지마
  • response.addHeader("Cache-Control", "no-store");: 저장하지마

Expires(만료시간)

  • response.setDateHeader("Expires", 0);
    • 0: 1970/1/1로 돌아감
    • long: milliseconds, int: seconds

캐싱 문제점

캐싱 이후에 서버사이드에서 데이터가 변경되더라도 제대로 적용하기가 쉽지 않음



  • 한번 캐싱된 거 계속 쓰느라 서버사이드에서 js 코드 변경이있엉도 완전히 반영안될 수 도 있음, 이를 방지하기 위해 밑의 방법!

캐싱되지않도록 js를 동적리소스로 인지시킴

<script type="text/javascript" src="<%=request.getContextPath() %>/js/sample.js?time=<%=(new Date()).getTime()%>"></script>

  • 요청마다 계속 쿼리스트링 바뀜 = 리퀘스트라인 바뀜 = 동적자원으로 인지함 = 캐싱절대안함
    • 하지만 너무 귀찮은 방법 -> 그렇다면 response header를 건드리자

MDN: Caching / Cache-Control

The Cache-Control HTTP/1.1 general-header field is used to specify directives for caching mechanisms in both requests and responses. Use this header to define your caching policies with the variety of directives it provides.

No caching

Cache-Control: no-store

The cache should not store anything about the client request or server response. A request is sent to the server and a full response is downloaded each and every time.

Cache but revalidate

Cache-Control: no-cache

A cache will send the request to the origin server for validation before releasing a cached copy.

Private and public caches

The "public" directive indicates that the response may be cached by any cache. This can be useful if pages with HTTP authentication, or response status codes that aren't normally cacheable, should now be cached.

On the other hand, "private" indicates that the response is intended for a single user only and must not be stored by a shared cache. A private browser cache may store the response in this case.

Cache-Control: private
Cache-Control: public

Expiration

The most important directive here is max-age=< seconds >, which is the maximum amount of time in which a resource will be considered fresh. This directive is relative to the time of the request, and overrides the Expires header (if set). For the files in the application that will not change, you can normally use aggressive caching. This includes static files such as images, CSS files, and JavaScript files, for example.

Cache-Control: max-age=31536000

Validation

When using the "must-revalidate" directive, the cache must verify the status of the stale resources before using it and expired ones should not be used. For more details, see the Validation section below.

Cache-Control: must-revalidate


Refresh

  • refresh.jsp : 서버사이드의 갱신데이터 조회 방법
    • 현재 서버의 시각 : <%=new Date() %>
      • 이렇게 시간이 보인다고 현재시간이라고 생각하니 .....?
      • 이건 이미 지나간 시간 이라구 !!!
      • 서버에서 시간을 얻어와보자!!!!
  • 예제) 서버타임 얻어오는 방식
    • 동기
      • java
      • html
      • js
    • 비동기
      • ajax
      • fetch
      • server-sent event

동기: 리로드 대잔치

java: setIntHeader("Refresh",1)

  • refresh 헤더: 동기방식으로 자동 요청을 처리할 때 사용됨
    • setHeader("Refresh","1")도 가능
  • "진짜" 현재 시각을 알려면 적어도 1초마다 요청이 발생되어야함
    • 그래서 1초마다 리로딩이 오지게됨...

html: http-equiv

  • <meta http-equiv="Refresh" content="5;url="https://www.naver.com">
    • 예: 리뉴얼되었읍니다 5초후 새로운 웹사이트로 갑니다요
  • request의 refresh에 상응하는 역할

js

  • <body>
    • $(document).ready(function(){}) 과 같음
function init() {
  setTimeout(() => {
    location.reload();
  }, 1000); // ★ 유의 ★ 람다식의 this는 언제나 window!!
}

비동기

  • 클라이언트들은 한번의 url 요청으로 갱신된 데이터를 받아오는 줄 알았겠지만... 사실은 물밑작업이 다이루어졌던거시다!!!!!!
  • long polling 방식
    • ajax, fetch
    • 긴기간을 잡아두고 단타로 요청을 계속 보내서 데이터 받아오는것
    • http 1.0에서 주로 사용했던 방식
    • 한계점 1. 서버에 너무 많은 부담
      • 서버 입장에서는 클라이언트 1명이 매 1초마다 요청을 계속 보내오는 것과 마찬가지. 만약 동시에 1000명이? 10000명이 왔으면? 이 클라이언트들이 전부 1초마다 요청을 발생시킨다면? 끄아아악 서버살려...
      • 2000년대초반 네이버,다음카페의 채팅구현방식
    • 한계점 2. 1초 미만에서 갱신되는 데이터는 확인 불가능 (ajax예시)
      • 우린 지금 시간을 second로 보고있는데 사실 시간은 picosecond, nanosecond도 있자나?
    • 그럼이제 모쓰죠?
  • long polling 단점 해결 방식: Server-Sent Event
    • Web Socket 도 있슈
    • 쪽지알림과 같은 push알림

Ajax

  • 단점: jquery 없으면 못 써먹음..
  • setInterval(): 주기적으로 요청이 넘어가도록
// getServerTime.jsp
<%@page import="java.util.Date"%>
<%@ page language="java" contentType="text/plain; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%=new Date()%>
let timeArea = $("#timeArea");

setInterval(() => {
  $.ajax({
    url : "getServerTime.jsp",
    method : "get",
    dataType : "text",
    success : function(resp) { // resp: 응답으로 돌아온 문자열
      timeArea.text(resp);
    },
    error : function(xhr) {
      console.log(xhr);
    }
  });
}, 1000); // 요청 주기 1초

Fetch

  • Fetch API: HTTP 1.1에서 새로 등장
let timeArea = $("#timeArea");
// 전역으로 빼두어서 그냥 쓰면되는데, 필기 편의상 복붙중

setInterval(() => {
  fetch("getServerTime.jsp") // 리턴타입: promise (then, failed를 콜백으로 씀)
  .then(funtion(response) {
    if(response.ok) { // success(ajax)
      console.log(response);
      return response.text(); // body데이터 꺼내기 위함. 하지만 아직 body 아닌 promise객체 리턴
      /*
       * ex)
       * 서버에서 문자열 1gb를 보내야하는 상황.
       * 1. 한번에 읽을 수 없고,
       * 2. 네트워크 대역폭때문에 쪼개져서 응답이 나가야함
       * (대역폭 1mb 이라면 1024개의 낱개 데이터(청크)로 내보내야 함)
       * 이런 상황때문에 데이터를 한번에 return  data로 넘기는 것이 아닌,
       * 다 모으면 바꾸라고 promise 객체로 넘긴다. (응답데이터 수신에 시간 소요 많기때문)
       * return type이 다시 promise이기 때문에 또 아래의 then 콜백함수가 작동함
       */
    }else { // 200외 다른 상태 코드: fetch와 ajax의 차이 = fetch:1 100~500 모두 resp로 도착
      console.log(response.status);
    }
  }).then(function(text) { // 응답데이터 수신이 완료되어 콜백 실행됨, 매개변수 = text
    timeArea.text(text);
  })
}, 1000);


  • body에 직접 접근하지않고 __proto__로 접근
    • fetch에서는 언마샬링이 자동으로 되지않고 resp가 원래 그대로 들어옴
      -> 직접 언마샬링을 해야함
      • proto의 json
      • proto의 text: 응답데이터를 json말고 text/plain
      • proto의 blob: fetch는 데이터타입에 제한이 없다는 것을 보여줌, 이진데이타도 가능, 파일업로드 다운로드도 가능하다는 것 (arrayBuffer도 사용가능)


  • 타입이 ajax때 보던 xhr아니고 fetch
  • request header에 xhr없어도 비동기 => xhr로 비동기 동기 식별 불가

Server-sent Event: Event Source

  • An EventSource instance opens a persistent connection to an HTTP server, which sends events in text/event-stream format.
  • 서로 소통이 가능한 웹소켓과 유사하지만, SSE는 서버만 클라이언트에게 메세지를 계속 푸시함
  • events: 데이터 (기존의 이벤트 개념 아님)
    • event-stream: 바이너리데이터 스트림
  • event handlers
    • EventSource.onopen
    • EventSource.onerror
    • EventSource.onmessage
  • method
    • EventSource.close()
      • http로 따지면 어림도 없음, http쓰면서 연결을 우리가 끊은 적이 없음
// getServerTime_SSE.jsp
<%@page import="java.util.Date"%>
<%@ page language="java" contentType="text/event-stream; charset=UTF-8"
    pageEncoding="UTF-8" buffer="8kb"%>
<%
boolean flag = true;
   	while(flag == true){
   		Thread.sleep(1000); // 1초의 갭
   		Date now = new Date();
%>
id:<%=now.getTime() %> <%-- 그냥 내보내면 뭔지 모르기때문에 식별자 필요--%>
event:test<%--type결정 --%>
data:<%=now%>
data:line data<%--라인 개행 따로 안해주니 \\n 한개라고 생각해서 한건의 데이타로 구별됨, 데이터구별하려면 n두번 --%>

<%
	out.flush(); // buffer 다 차지않아도 flush하겠다
   	}
%>
let timeArea = $("#timeArea");
// 전역으로 빼두어서 그냥 쓰면되는데, 필기 편의상 복붙중

let es = new EventSource("getServerTime_SSE.jsp");
es.onopen = function(event){
  console.log(event);
}
/*
// 아래의 3가지 방식중 하나 사용
// 1. type이 message 일때
es.onmessage = function(event) {
  console.log(event);
  timeArea.text(event.data); 
  // timeArea가 밑에서 선언되어도 사용할 수 있음
  // -> 선언 이후에 function이 실행되기때문
}

// 2. type을 test로 변경했을 때 (SSE.jsp 참조)
// 2-1. jquery 이용
// 이 방식을 그냥 사용할 경우 시간이 화면에 나오지 않음
// -> $사용으로 jquery이벤트로 전환되었기때문
$(es).on("test", function(event) {
  console.log(event);
  timeArea.text(event.originalEvent.data); // 해결방안: js이벤트로 다시 변경
}
*/
// 2-2. 기본 js 사용
es.addEventListener("test", function(event) {
  console.log(event);
  timeArea.text(event.data);
}

es.onerror = function(event) {
  if(event.target.readyState != EventSource.CLOSED) { // 에러 발생 후에도 연결이 유지되고 있다면
    ex.close(); // 연결 끊어라. 
    // 이렇게 명시적으로 중단하지 않는다면?
    // -> es가 스트림 데이터를 계속 가져와야한다고 생각하고 3-5초 간격으로 새로고침(서버에 요청)을 계속함
  }
}

onmessage

  • message: id/type/data중 type에 따라 달라짐
    • type이 test라면 ontest

onerror (sse.jsp만들기전)

  • EventSource의 상수
    • CONNECTING: 0
    • OPEN: 1
    • CLOSE: 2
  • onerror의 if 주석안할떙
  • onerror의 if 주석 처리 : 계속 3-5초간격으로 요청 넣음

SSE 정리

  • SSE의 장단점
    • 장점: 부하는 덜걸림
    • 단점: 대부분의 클라이언트는 잠깐 사용했다가 사용이 끝나면 네트워크를 떠나는데 서버에서 무한루프돌리면서 하는게 과연 맞을까...?
  • SSE에서 유의할 점
    • 푸쉬할때 중요한건 적절한 시점에 끊어줘야함 (close이용)
      • 하지만 close를 해줘도 서버에서 계속 무한루프 돌고있을 수도 있음
      • close는 클라이언트 사이드만 종료되는 것이기때문
      • 역시 서버에서도 중단하는게 있어야함
  • long polling 과의 차이
    • 연결수립은 1번 데이터는 계속 받아옴

Location

-flowControl.jsp

Forward, Include vs. Redirect

  • forward, include vs. redirect
    • state를 유지할 것이냐 stateless로 할것이냐

프롤로그...

  • Http: Connectless, Stateless
    • stateless
      • Client --request--> Server
      • ① req 생성 - ② resp 생성 - ③ resp 송출 - ④ 연결 끊김 - ⑤ req,resp 사라짐
      • ⑥ 같은 Client가 와서 또 요청하면 새로 다 생김
      • -> 같은 Client라는거 식별불가 = 이거시 stateless
      • 님 아침머겅성? 아뇨 / 님 아침머겅성? 아뇨 / 님 아침머겅성? 아뇨
      • -> 상태 저장이안되서 물어본 거 까먹고 계속 이럼, 대화가 안됨
    • 보완하려고 cookie, session 등장

1) state 유지: FORWARD, INCLUDE

  • 처리 중간에 resp나가면 안됨
    • 그 순간 req 사라져버림 -> req안 데이터 사라져서 stateless가 되버리기때문

FORWARD = 위임 방식, dispatch 방식

  1. 클라이언트: A에게 요청
  2. 서버 내에서 A -> B로 이동 (서버 내 이동 = 서버사이드 경로 이용)
  3. 클라잉너트: 응답받으면 클라이언트는 a에게 요청해서 받은 것이기 때문에 a한테 왔다고 생각함
  • B의 존재 모름, A -> B이동사실 모름
  • 이 역시 모델2!!
  • 모델1구조에서 모델2구조로 갈때 많이 활용되는것 = 포워드

INCLUDE

클라이언트 -> a -> b -> 다시 a -> 클라이언트

  • a와 b에서 만들어진 데이터가 하나로 합쳐서 클라이언트에게 나감
  • a가 b를 내포(include)하고있다
  • 응답데이터: page 1개 (하지만 2개 이상의 jsp에서 만들어지는것) => 페이지 모듈화
  • 페이지모듈화시 많이 활용되는것 = 인클루드

2) stateless: REDIRECT

  1. 클라이언트가 A에게 요청
  • A가 만든 req(1번)는 사라져버림
  1. A에서 다시 클라이언트에게로 응답내보냄 -> Forward, Include와의 차이
  • resp에 제대로된 message body 없이 response line, header만 구성됨
  • 대신 resp에 (B에 대한 정보 + 이 응답 데이터는 body가 없다는 메시지 + SC) 내보내야됨
    • status code(302, 307: moved, 여기로 이사갔어요)
  1. 클라이언트가 A의 resp를 뜯어봤더니 302가 까꿍 -> 아하! 하고 헤더에 로케이션찾아서 다시 요청보냄
  2. 다시 클라이언트가 B에게 요청함
  • 이때 새로운 req(2번)가 생김
  1. B에서 최종응답 내보냄
  • 최종응답데이터는 4마지막단계 b에서 나가는 데이터

요약
① B를 찾기 위해 A로 클라이언트가 요청보냄
② A가 님이 찾는 B 여기 없어요 하고 응답 보내면서, B의 위치와 상태코드 내보내야함 -> 이때 위치를 헤더 location에 셋팅

  • stateless: req 1번,2번은 서로 상관 없음
  • 클라이언트: B의 존재 인지, 왜냐면 4번 단계에서 b에게 새로운요청을 보냈기때문
  • 사용예시
    • 로그인 처리 과정
      • 네이버에서 검색하다가 이메일 탭을 누르면 로그인하라고 먼저나옴로그인성공하면 다시 메일페이지로 보내줌,
      • 로그인페이지 받아 -> id/pw입력 -> 로그인해 -> 서버가 인증수행 -> 인증성공해 -> 메일 페이지로 보내야돼 -> 여기서 f,i,r중 골라야지 -> 이제 id/pw 필요업서 -> 그럼 이제 첫번째 받은 요청 필요없어 다써먹었으니까 갖고잇어봣자 괜히 서버만 무거워짐 -> 근데 이거없으려면 응답데이터 내보내야 req 없앨 수 있음 -> 그래서 리다이렉트사용 (resp 내보냄: 여기로가세요, 상태코드는이겁니다) -> 그걸 받고 클라이언트가 다시 요청받고 재요청ㄱㄱ

redirect 예시



  • 302로 온 응답데이터(flowControl.jsp)의 헤더 중 로케이션 == cacheControl.jsp 의 리퀘스트라인



오늘 수업 정리

  • js에서 요청 발생시키는 여러 방법
  • setTimeOut vs setInterval
  • refresh헤더를 통한 주기적인 동기요청
    • refres헤더쓰면 동기요청되기때문에 페이지전체 로드..
    • data만 필요할땐 전체 ui다바꿀 필요없으니 비동기
    • 비동기에는 refresh적용안됨요
  • longpolling: fetch, ajax
    • 단점: 서버를 계속 괴롭힌다
  • server-sent event
    • longpolling단점개선
    • 그렇다고 무조건 sse를 쓰라는건아님
    • 상황에 따라 적절히
  • 젤중요한건 mozilla doc보는것!!!@@@

과제

  • 만들어라 과제는 다음다음주에 계속할겨..
  • 중프소스 ajax에 fetch 적용, ajax를 sse로 적용해보고 ,, 차이점,, (커밋nono)
profile
갈 길이 멀다

0개의 댓글