TIL - 0525

ajax로 서버에 콜하기

  • ajax란?
    1. asyncronous javascript and xml의 줄임말
    2. 비동기로 서버에 요청을 하고, 응답 데이터를 받아 랜더링까지 하는 기술 : 백그라운드 작업, 부분적으로 새로고침 효과를 얻을 수 있음
    3. 응답 데이터로 초기에는 xml을 사용하다가 json을 사용함
  • json이란?
    1. 자바스크립트는 아니지만 자바스크립트의 객체 문법처럼 짜인 데이터
    2. key - value로 맵핑되어있음 : 변수에 json을 할당하면 변수.key로 value를 찾을 수 있음
    3. json docs 보기
  • xml 대신 json을 사용하는 이유?
    1. 가벼움 : xml은 마크업 언어로 의미있는 태그 내에 데이터가 감싸져있는 형태 - 필요한 데이터보다 부수적인 데이터 용량이 더 큼
    2. 필요한 데이터를 파싱하기위해 더 많은 작업을 해야함 : 27에서 27을 꺼내기위해 찾아가야함
  • @RestController : 처리 결과를 뷰 리턴이나 redirect를 리턴하지않고, String을 리턴할 수 있는 컨트롤러 선언 어노테이션
    • Jackson 라이브러리 사용을 통해 Entity를 json으로 변환하여 json 데이터를 리턴할 수 있음 : Answer를 리턴해도 라이브러리 덕분에 json으로 변환해서 리턴
    • entity의 attribute에 Jackson에서 제공하는 어노테이션 적용을 통해 json 데이터화 하지않을 것을 설정할 수 있음 : 할 것만 설정할 수도 있음
/* controller */
@RestController
@RequestMapping("/api/questions/{questionId}/answers")
public class ApiAnswerController {
    private static final Logger log = LoggerFactory.getLogger(ApiAnswerController.class);

    @Autowired
    private AnswerRepository answerRepo;

    @Autowired
    private QuestionRepository questionRepo;

    @PostMapping
    public Answer create(@PathVariable("questionId") Long questionId, String contents, HttpSession session) {
        log.info("answer contents : {}", contents);
        Answer answer = Answer.builder().user(HttpSessionUtils.getUserFromSession(session).get()).question(questionRepo.findById(questionId).get()).contents(contents).build();
        return answerRepo.save(answer);
    }

}

/* answer entity */
@NoArgsConstructor
@Getter
@Setter
@ToString
@Entity
public class Answer extends TimeEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn(foreignKey = @ForeignKey(name = "fk_answer_user"))
    private User user;

    @ManyToOne
    @JoinColumn(foreignKey = @ForeignKey(name = "fk_answer_question"))
    private Question question;

    @Column(nullable = false, columnDefinition = "TEXT")
    private String contents;

    @Column(nullable = false)
    @JsonIgnore
    private boolean deleted = false;
    .
    .
    .
}
  • ajax 요청 - 응답 코드
    • ajax 요청 시 콜백함수(응답이 돌아왔을 때) 등록
    • JSON 데이터를 파싱할 수 있는 자바스크립트 객체 : JSON
    • jquery 적용으로 더 간결하게 코드를 짤 수 있지만 jquery에 의존하는 코드를 짜지않기위해 자바스크립트 문법 그대로 짰음
/* html : trigger */
<form class="submit-write" id="submit-answer" action="/api/questions//answers" method="post">
	<div class="form-group" style="padding:14px;">
		<textarea id="answer-editor" class="form-control" placeholder="Update your status" name="contents"></textarea>
	</div>
	<button class="btn btn-success pull-right" type="button" onclick="answerWrite()">답변달기</button>
</form>

/* script.js */
function answerWrite() {
    var req = new XMLHttpRequest();
    var form = document.getElementById("submit-answer");
    req.open('POST', form.action);
    req.setRequestHeader('Accept', 'application/json');
    req.addEventListener('load', function(){
        responseHandle(req);
    }, false);
    req.send(new FormData(form));
}

function responseHandle(req) {
    if (req.status != 200) {
        console.log('answer write err!!');
        return;
    }
    var data = JSON.parse(req.responseText);
    var arr = [data.user.name, data.modifiedDate, data.contents, data.id, data.question.id, data.id];
    var template = document.getElementById('answerTemplate').innerHTML;
    for (var i = 0; i < arr.length; i++) {
        template = template.replace(new RegExp("{[0-9]}"), arr[i]);
    }
    var contents = document.createElement('div');
    contents.innerHTML = template;
    contents = contents.firstElementChild;
    document.querySelector(".qna-comment-slipp-articles").prepend(contents);
    document.getElementById('answer-editor').value = '';
}

웹 기초

인터넷 : 전세계인을 연결할 수 있는 연결망

  • LAN을 먼저 사용했고, LAN을 확장시켜 외부에서도 연결시킬 수 있게 통신망 설비를 갖춤
  • 인터넷 사용료를 우리가 내는 이유는 국가에서 특정 통신사에만 통신망을 갖출 수 있게 허가를 내주었기때문에 -> 통신망을 갖춘 통신사에 일정 비용을 내고 외부로 접속할 수 있는 네트워크를 사용할 수 있음

최초의 인터넷을 사용한 웹 통신 : 팀 버너스리 연구소

  • 문서를 주고 받기위해 고안해냄
  • 프로토콜이 존재함 : HTTP(Hyper Text Transfer Protocol)
  • 하이퍼텍스트란 하이퍼링크(A문서 -> B문서로 넘어갈 수 있는 텍스트, 문서 간의 연결)로 작성되어있는 문서

브라우저의 역할

  • 최초에는 .html 정적인 문서만 보여줄 수 있었지만 브라우저의 발전으로 더 다양한 문서를 보여줄 수 있게됨
  • 브라우저도 프로그램
  • 브라우저의 내부 모습 : 랜더링 엔진, 자바스크립트 엔진, 통신(프로토콜 기반 메세지 작성, 실제 통신은 다른 프로그램) 등
  • 참고 문서

통신설비 + 클라이언트 + 서버

  • 인터넷은 환경이고, 환경을 제대로 사용할 수 있는 프로그램이 클라이언트와 서버 프로그램
  • 인터넷이라는 거대한 연결 설비가 갖춰져있지않았다면, 지금처럼 발전된 웹 서비스를 사용하지못했을 것
  • 클라이언트와 서버 프로그램의 발전으로 고품질 서비스를 이용할 수 있음
  • 웹서버에는 아파치, NginX가 있음

HTTP

  • 주고 받기를 하기위해선 서로 간의 약속이 필요함 : 떨어져있기때문에
  • HTTP에서 중요한 것
    1. 무엇 : URI (리소스, 다룰 수 있는 자원 - 자원의 고유값, 예전에는 파일명 그대로를 노출시켰지만 요즘은 리소스명 + 리소스의 id값을 사용함)
    2. 누구에게 + 무엇을 : URL
    3. 어떻게할까 : HTTP 메소드
    4. 어떻게 처리했다 : HTTP 응답코드

CGI

  • 동적인 문서 만들기에 관심
  • CGI : 그에 따른 웹서버와 프로그램(c와 같은 프로그래밍 언어로 짜여진 프로그램) 간의 통신을 하기위한 약속
  • 요청을 받을 때 비로소 프로세스로 되기때문에 동작이 느림

WAS

  • CGI 기반 프로그램과 똑같은 역할을 함
  • 만들어진 프로그래밍 언어가 다름 : 각각의 WAS 마다 장점이 있음

웹어플리케이션 프레임워크

  • 웹어플리케이션 서버 기술을 추상화하여 개발자가 기능 구현에만 집중할 수 있도록 함 : 보통 내장 웹서버가 있음(변경도 가능)
  • spring(servlet 추상화), rails(ruby의 웹 관련 API 추상화), express(nodejs에서 제공하는 자바스크립트 API 중 웹 관련 기술 추상화)

IP와 포트번호

  • IP는 네트워크에 연결되어있는 기기의 식별자
  • 포트번호는 소켓의 식별자 : 포트번호는 약속된 번호 이외에 임의로 지정할 수 있고, 수신자(클라이언트)의 경우에는 프로토콜 스택이라는 통신을 담당하는 OS 프로그램에 의해 통신할 때 임의로 번호가 부여됨(같은 IP에 대한 처리라도 서버에서 받은 제어 정보에 의해 포트번호를 식별할 수 있으므로 각각 응답해줄 수 있음)

쿠키와 세션

  • HTTP는 상태를 저장하지않는다 : 상태란 이전 통신의 상태, 이전 요청자가 누군지 이전 응답자가 누군지, 어떤 통신을 했는지 전혀 모른다.
  • 단점이라면 요청을 할 때마다 이전에 나야! 라는 것을 알려줘야하는 것
    • 해당 단점을 극복하기위해 쿠키라는 것이 고안되었는데 쿠키란 이전 상태값을 저장하기위해 클라이언트에 파일 형태로 저장하는 것을 말함
  • 쿠키의 단점이라면 매번 통신할 때마다 이전 통신 상태(ID, 비밀번호 등 민감한 내용들) 서버와 통신할 때 패킷에 실어보내야한다는 것
    • 만약 중간에서 누군가 패킷을 들여다본다면? 위험하다
    • 그래서 고안된 것이 세션이다 : 세션도 똑같이 쿠키를 사용한다, 그러나 담는 내용이 다름(서버에서 발급해준 세션ID만을)
  • 세션 ID가 탈취당하면? 그래서 만료기간을 보통 서버에서 두고 있다(이외에도 인증방법이 또 있겠지 - HTTPS?)
    • 보통 만료기간은 프로세스가 종료되었을 때(크롬의 경우 탭마다 프로세스라서 탭이 닫히면 끝)
    • 만료기간을 서버에서 설정해줄 수 있음

네트워크

데이터 송수신 동작이 끝나면

  • 웹의 경우에는 서버에서 close() 메세지를 보냄 : 서버측에서 TCP 헤더의 컨트롤비트 FIN(1)로 기록하고 패킷을 보냄
    • HTTP 1.0은 서버에서 close()가 올 경우 클라이언트에서 끊기 작업에 바로 들어가지만 1.1부터는 리퀘스트 메세지를 보내도 좋도록 되어있음 : 클라이언트에서 먼저 끊기 가능
  • 클라이언트에서도 서버의 close() 메세지를 받았다는 확인으로 패킷을 전송함 : ACK 번호(수신측에서 받았다는 의미로)
    • 어플리케이션에 데이터를 넘겨줄 대기를 함 : 요청 결과
  • 소켓은 바로 없애버리지않음 : 연결이 끊겼다고 하더라도 얼마정도 기다렸다가 소켓을 말소시킴
    • 웹의 경우에는 서버가 먼저 close()를 하지만 어플리케이션에 따라 클라이언트가 먼저 close()를 할 때도 있음, close() 패킷을 보낸 후 바로 소켓을 없애버리면 서버에서는 그것도 모른채 확인 패킷을 또 보냈을 경우 해당 IP + 포트가 우연히 일치하는 소켓이 생성되어있다고 했을 때 해당 요청에 대해 FIN을 보내고 연결이 종료되어버릴 수 있기때문에 바로 말소를 시키지않음
    • 클라이언트의 포트번호는 임의로 할당됨 : 포트번호는 네트워크 동작을 해야 할당, 문을 열어두는 의미, 결과적으로 어떤 네트워크 프로그램인지 알 수 있음