과목명 : 웹 서버 프로그래밍(Web Server-side programming with Node.js)
수업일자 : 2023년 03월 30일 (목)
1. Front-end(Client side) JavaScript : AJAX(Asynchronous JavaScript and XML)
1-1. AJAX의 정의
- AJAX(Asynchronous JavaScript And XML)은 자바스크립트를 이용해 서버와 클라이언트가 비동기 방식으로 데이터를 교환할 수 있는 통신 기능이며 빠르게 동작하는 동적인 웹 페이지를 개발하기 위한 기법 중 하나입니다.
- 표현 정보를 위한 HTML, CSS 동적인 디자인, 기능, 서버 - 클라이언트 간의 상호작용을 위한 DOM(Document Object Model), 자바스크립트
1-2. AJAX의 특징
(1) 기본적으로 *XML, *JSON 형식으로도 통신할 수 있습니다.
(2) 비동기적이고 동적인 웹 서비스를 구현하기 위한 방법입니다.
(3) 페이지의 별도 이동없이 서버에 요청을 보내고 응답을 받는 기술입니다.
(4) * jQuery나, *Axios와 같은 라이브러리도 사용 가능합니다.
1-3. XML, jQuery, JSON?
(1) XML(Extensible Markup Language)
- W3C에서 개발된 다른 특수 목적을 갖는 마크업 언어를 만드는데 사용하도록 권장하는 다목적 마크업 언어로써 다른 많은 종류의 데이터를 기술하는데 사용될 수 있습니다.
(2) jQuery
- HTML의 클라이언트 사이드 조작을 단순화하기 위해 설계된 크로스 플랫폼 기반 자바스크립트 라이브러리입니다.
(3) JSON(JavaScript Object Notation)
- 자바스크립트의 객체를 기술하는 문법으로 구조화된 데이터 포맷을 표현하기 위한 표준 형식입니다.
(4) Axios
- 브라우저, Node.js를 위한 Promise API 기반 기술을 이용하는 HTTP 비동기 통신 라이브러리입니다.
- 서버(Back-end) 사이드와 클라이언트(Front-end) 사이드 간 통신을 용이하게 하기 위해 AJAX와 함께 사용하기도 하는 라이브러리입니다.
1-4. 비동기(Asynchronous) 방식
(1) 웹 페이지를 리로드하지 않고 필요한 데이터만 불러올 수 있습니다.
- 장점 : 이미지, 스크립트, 코드 등 필요한 데이터만 가져와서 사용이 가능합니다.
1-5. AJAX : 서버로 요청을 보내는 코드 (GET 방식 사용)
<script>
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
// 사용자 request에 대한 콜백
if (xhr.readyState === xhr.DONE) {
// 요청이 완료된다면
if (xhr.status === 200 || xhr.status === 201) {
// 서버 접속에 성공 시
console.log(xhr.responseText);
// 서버에서 보내는 data
} else {
console.error(xhr.responseText);
}
}
};
xhr.open('GET', 'https://www.zerocho.com/api/get');
xhr.send();
</script>
(1) 라이브러리 사용 없이, 브라우저가 지원하는 XMLHttpRequest 객체를 사용합니다.
(2) open() 메소드에 HTTP 요청 메소드와 주소를 적고, send() 메소드로 전송합니다.
(3) GET 방식
- 클라이언트의 요청 정보가 URL에 노출됩니다. (보안에 취약할 수 있음.)
1-6. HTTP Request : GET, POST 방식의 특징
(1) GET
- HTTP 통신에서 사용되는 메소드로써 클라이언트에서 서버로, 어떠한 리소스로부터 정보를 요청하기 위해 사용되는 메소드입니다.
- GET 메소드를 이용한 요청은 URL 주소 끝에 요청하는 값에 대한 파라미터가 포함되어 전송되고 이 부분을 Query string이라고 부릅니다.
- GET 요청은 파라미터에 모든 정보가 노출되기 때문에 주요 정보를 다룰 때 GET 메소드 사용이 권장되지 않습니다.
(2) POST
- HTTP 통신에서 사용되는 메소드로써 클라이언트에서 서버로, 리소스를 생성하거나 업데이트 또는 데이터를 보낼 때 사용되는 메소드입니다. (Ex : 게시판에 글을 작성한다고 할 때 POST 메소드 사용)
- POST 방식은 전송 데이터를 HTTP Message Body 부분에 담아서 서버로 전송합니다.
(Body 타입의 경우 Content-Type 헤더에 따라 결정됩니다.)
- POST 방식의 경우 전송 시 담는 데이터에 대한 제한이 없고, GET 방식처럼 URL에 요청 파라미터를 작성하지 않기 때문에 보안 측면에서 더 우수하므로 보안적인 요청 작업이 존재할 때 일반적으로 POST 방식을 사용합니다.
1-7. GET, POST 방식의 차이점
(1) 목적성에 따른 차이
- GET은 서버의 리소스에서 데이터를 요청할 때, POST는 서버의 리소스를 새로 생성하거나 업데이트 시 사용합니다.
(2) HTTP Message Body의 유무
- GET은 요청 목적으로 HTTP Message에 Body가 존재하지 않고 POST는 리소스의 생성, 업데이트 목적으로 Body가 존재합니다.
(3) 멱등성(Idempotent)
- 멱등성(Idempotent)이란, 컴퓨터 과학에서 연산을 여러 번 하더라도 결과가 달라지지 않는 성질을 뜻하지만, HTTP 통신에서는 동일한 요청을 한 번 보내는 것과, 여러 번 연속적으로 보내는 것이 같은 효과를 지니고 서버의 상태도 동일하게 유지될 때 HTTP 메소드가 멱등성을 가지고 있다고 표현합니다. GET 방식은 멱등성을 가지며 POST 방식은 멱등성을 가지지 않습니다. (공식 Reference : MDN Web docs 문서)
1-8. onreadystatechange 프로퍼티 대신 onload와 onerror EventListener로 요청에 대한 성공 및 실패 확인 가능
(1) xhr.status는 요청에 대한 응답 코드(200번 영역은 성공, 400번 영역은 클라이언트 에러, 500번 영역은 서버 에러)를 xhr.responseText에서 확인할 수 있습니다.
<script>
var xhr = new XMLHttpRequest();
xhr.onload = function() {
if (xhr.status === 200 || xhr.status === 201) {
console.log(xhr.responseText);
}
};
xhr.onerror = function() {
console.error(xhr.responseText);
};
// 요청 메소드와 이에 대한 주소 설정
xhr.open('GET', 'https://www.zerocho.com/api/get');
// 요청 전송
xhr.send();
</script>
1-9. POST 방식으로 요청하는 코드
(1) 데이터를 담아 서버로 보내는 경우
<script>
var xhr = new XMLHttpRequest();
var data = {
name: 'zerocho',
birth: 1994
};
xhr.onreadystatechange = function() {
if (xhr.readyState === xhr.DONE) {
if (xhr.status === 200 || xhr.status === 201) {
console.log(xhr.responseText);
} else {
console.error(xhr.responseText);
}
}
};
xhr.open('POST', 'https://www.zerocho.com/api/post/json');
xhr.setRequestHeader('Content-type', 'applicaiton/json');
// Content-type을 JSON 형식으로 설정
xhr.send(JSON.stringify(data)); //데이터를 담아 전송한다.
</script>
(2) 실제로 코드를 런타임 환경에서 확인해 보면, 해당 콘솔이 아니기 때문에 CORS 정책 오류가 발생합니다.
2. FormData
2-1. FormData 객체
- 보통 HTML의 <form> 태그를 이용해 input 속성으로 서버에 데이터를 전송할 수 있지만 자바스크립트에서는 FormData() 객체를 이용해서 데이터를 전송할 수도 있습니다. 동적인 기능을 할당하는 자바스크립트 영역에서 데이터를 전송할 수 있는 객체로 볼 수 있습니다.
2-2. FormData 객체의 여러 가지 메소드
(1) FormData.append()
- 데이터를 하나씩 추가합니다.
(2) FormData.has()
- 데이터의 존재 여부를 확인합니다.
(3) FormData.get()
- 데이터를 조회합니다.
(4) FormData.getAll()
- 모든 데이터를 조회합니다.
(5) FormData.delete()
- 데이터를 삭제합니다.
(6) FormData.set()
- 데이터를 수정할 수 있으며 기존 데이터 존재한다면 해당 데이터를 덮어쓰게 됩니다.
<script>
var formData = new FormData();
formData.append('name', 'zerocho');
formData.append('item', 'orange');
formData.append('item', 'melon');
formData.has('item'); // true
formData.has('money'); // false;
formData.get('item');// orange
formData.getAll('item'); // ['orange', 'melon'];
console.log(formData.getAll('item'));
formData.append('test', ['hi', 'zero']);
console.log(formData.getAll('test'));
formData.get('test'); // hi, zero
formData.delete('test');
formData.get('test'); // null
formData.set('item', 'apple');
formData.getAll('item'); // ['apple'];
console.log(formData.getAll('name'));
</script>
<실행 결과>
2-3. FormData 객체를 이용해 POST 요청 보내기
(1) xhr.send() 메소드에 formData를 인자로 주어 Form data를 전송할 수 있습니다.
<script>
var xhr = new XMLHttpRequest();
var formData = new FormData();
formData.append('name', 'zerocho');
formData.append('birth', '1994');
xhr.onreadystatechange = function () {
if (xhr.readyState === xhr.DONE) {
if (xhr.status === 200 || xhr.status === 201) {
console.log(xhr.responseText);
} else {
console.error(xhr.responseText);
}
}
};
xhr.open('POST', 'https://www.zerocho.com/api/post/formdata');
// form data 객체를 전송한다.
xhr.send(formData);
</script>
<실행 결과>
3. encodeURIComponent(), decodeURIComponent() 함수
(1) 가끔 주소 입력 시 한글이 존재하면 해당 URL을 서버가 처리하지 못하는 문제가 발생할 수도 있습니다.
- 만약 예시 주소가" https://localhost:8003/search/노드" 라고 가정해 본다면 한글 부분을 인코딩해 주어야 합니다.
- 사용 함수 : encodeURIComponent()
<script>
// encodeURIComponent, decodeURIComponent test
var xhr = new XMLHttpRequest();
// 요청에 대한 callback
xhr.onreadystatechange = function() {
// 요청이 완료되면
if(xhr.readyState === xhr.DONE) {
if (xhr.status === 200 || xhr.status === 201) {
// 서버에서 보내주는 값
console.log(xhr.responseText);
} else {
console.error(xhr.responseText);
}
}
};
// 한글 주소를 인코딩한 후 전송한다.
xhr.open('GET', 'https://www.zerocho.com/api/search/' + encodeURIComponent('노드'));
// 요청 전송
xhr.send();
</script>
<실행 결과>
(2) 반대로 decodeURIComponent() 함수를 사용하면 인코딩된 문자열을 디코딩하여 기존 텍스트를 확인할 수 있습니다.
decodeURIComponent('%EB%85%B8%EB%93%9C') // 노드
4. Data set, Data attribute
4-1. Data set 속성
- Data set(데이터 셋) 속성의 경우 HTML5에서 새롭게 추가된 문법으로 커스텀 사용자 속성을 이용해 DOM 요소에 접근하는데 표준화된 방법을 제공합니다. 자바스크립트에서 변수를 사용하듯이, 일종의 HTML 태그에도 변수를 달아주는 것으로 생각해 볼 수도 있습니다.
- HTML 태그에 데이터를 저장하는 방법으로 서버의 데이터를 클라이언트 사이드(엔드 포인트)로 내려줄 때 사용할 수 있습니다.
(1) 문법
<특정 태그 ... data-속성명 = 속성값 ...> ... </특정 태그>
(2) 자바스크립트에서 태그 이름.dataset.속성명으로 해당 태그에 접근할 수 있습니다.
ex) data-user-job → dataset.userJob, data-id → dataset.Id
(3) 반대로 자바스크립트에서 dataset에 값을 할당하면 태그에 해당 dataset에 대한 속성이 추가됩니다.
ex) dataset.monthSalary = 10000; → data-month-salary = "10000"
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<li id='num1' data-id="1" data-user-job="programmer">Zero</li>
<li id='num2' data-id="2" data-user-job="designer">Nero</li>
<li id='num3' data-id="3" data-user-job="programmer">Hero</li>
<li id='num4' data-id="4" data-user-job="ceo">Kero</li>
</body>
</html>
<script>
console.log(document.querySelector('#num1').dataset);
document.querySelector('#num1').dataset.monthSalary = 1000;
console.log(document.querySelector('#num1').dataset);
document.querySelector('#num1').dataset.userJob = "player";
console.log(document.querySelector('#num1').dataset);
</script>
<실행 결과>
5. REPL : Read - Eval(Evaluation) - Print - Loop
5-1. REPL
- REPL(Read - Eval(Evaluation 또는 Evaluate) - Print - Loop)의 약어로 사용자가 특정 코드를 입력하면 해당 코드를 검사하고 실행 결과를 출력해 주는 환경을 의미합니다.
- 자바스크립트 기반인 Node.js에서도 REPL 환경을 지원하기 때문에 학습 중 알게된 간단한 구문을 직접 코드로 입력해 보고 출력 결과를 확인해 볼 수 있습니다.
- Node를 정상적으로 설치했다면 Windows는 Command prompt, Mac은 Terminal에서 실행할 수 있습니다.
- 간단한 코드를 테스트할 때는 용이하지만 긴 코드를 작성하기엔 부적합합니다.
- 다른 언어도 REPL 기능을 지원하는 언어가 있으며 대표적인 동적 언어인 Python의 경우 IDLE을 지원합니다.
6. .js 파일을 이용해 Console 환경에서 파일 실행, 모듈(Module)로 구성하여 실행
6-1. 자바스크립트 파일을 생성하여 node 커맨드로 직접 파일 실행
(1) Windows 기준 Command prompt를 실행하고 cd 커맨드로 자바스크립트 파일이 존재하는 디렉토리로 이동합니다.
(2) 예시 코드를 작성합니다.
// helloWorld.js
function helloWorld() {
console.log('hell world');
helloNode();
}
function helloNode() {
console.log('hello node');
}
helloWorld();
(3) node command를 이용해 해당 helloWorld.js 파일을 실행시킨 후 출력 결과를 확인합니다.
6-2. 모듈(Module)
- 자바스크립트에서 모듈은 개발하는 애플리케이션의 규모가 커지게 되면 이후에는 반드시 파일을 여러 개로 분리해야 하는 시점이 오게 됩니다. 이때 분리된 파일을 각각 모듈(Module)이라고 부르고 이러한 모듈은 대게 클래스 하나 혹은 특정한 목적을 갖는 복수의 함수 라이브러리로 구성될 수 있습니다.
- 모듈은 특정한 기능을 수행하는 함수나 연관된 변수(데이터)들의 집합으로 볼 수 있습니다.
(1) Node는 자바스크립트 코드를 모듈로 만들 수 있습니다.
(2) 모듈로 만들면 여러 프로그램에서 재사용이 가능합니다.
6-3. 직접 모듈을 생성해 보기 (var.js, func.js, index.js)
- 동일한 디렉토리에 var.js, func.js, index.js 파일을 생성해 아래와 같이 코드를 작성합니다.
(1) var.js
const odd = 'odd number';
const even = 'even number'
module.exports = {
odd,
even,
};
(2) func.js
const { odd, even } = require('./var');
function checkOddOrEven(num) {
if (num % 2 === 1) {
return odd;
}
return even;
}
module.exports = checkOddOrEven;
(3) index.js
const { odd, even } = require('./var');
const checkNumber = require('./func');
function checkStringOddOrEven(str) {
if (str.length % 2 === 1) {
return odd;
}
return even;
}
console.log(checkNumber(10));
console.log(checkStringOddOrEven('hello'));
<index.js 최종 실행 결과>
6-4. var.js, func.js, index.js 파일 간의 모듈 관계
(1) 비구조화 할당(Destructuring assignment)
- index.js 파일에서 odd, even의 속성 부분은 var.js의 module.exports를 비구조화 할당을 한 사실을 알 수 있습니다.
const { odd, even } = require('./var');
(2) require와 module.exports
7. Node에 내장된 객체들(global, console)
7-1. global
(1) global 객체의 경우 Node의 전역 객체(Global object)에 해당함으로써, 모든 객체의 유일한 최상위 객체입니다.
(2) 클라이언트 사이드의 엔드 포인트인 브라우저에서는 window 객체, 서버 사이드에서는 global 객체가 존재합니다.
(3) 브라우저의 window 객체와 같은 역할로 볼 수 있으며 모든 파일에서 접근할 수 있습니다.
(4) window 객체처럼 생략 가능합니다. (console, require도 global 속성)
7-2. global 속성 공유
(1) global 속성에 값을 대입하면 다른 파일에서도 사용할 수 있습니다.
- globalA.js
module.exports = () => global.message;
- globalB.js
const a = require('./globalA');
global.message = 'hello js';
console.log(a());
<globalB.js 실행 결과>
7-3. console 객체
- console 객체의 경우 디버깅 처리를 위해 존재하는 객체입니다.
- 아래는 console 객체에 존재하는 여러 가지 함수들입니다.
(1) console.time() / console.timeEnd()
- time() ~ timeEnd() 사이에 발생한 작업들의 시간을 측정합니다.
(2) console.log()
- 인자로 넘겨준 값을 콘솔에 출력합니다.
(3) console.error()
- 오류 메시지를 콘솔에 출력합니다.
(4) console.dir(객체 또는 옵션)
- 인자를 통해 전달된 객체를 콘솔에 출력합니다. 만약 옵션값까지 전달되었다면 옵션까지 적용하여 출력하게 됩니다.
(5) console.trace()
- 오류 메시지를 추적할 때 사용합니다.
const string = 'abc';
const number = 1;
const boolean = true;
const obj = {
outside: {
inside: {
key: 'value',
},
},
};
console.time('전체시간');
console.log('평범한 로그입니다 쉼표로 구분해 여러 값을 찍을 수 있습니다');
console.log(string, number, boolean);
console.error('에러 메시지는 console.error에 담아주세요');
console.table([{ name: '제로', birth: 1994 }, { name: 'hero', birth: 1988}]);
console.dir(obj, { colors: false, depth: 2 });
console.dir(obj, { colors: true, depth: 1 });
console.time('시간측정');
for (let i = 0; i < 100000; i++) {}
console.timeEnd('시간측정');
function b() {
console.trace('에러 위치 추적');
}
function a() {
b();
}
a();
console.timeEnd('전체시간');
<console.js 실행 결과>
8. Reference
Node.js 교과서(Node.js Textbook) - 저자 : 조현영
https://www.zerocho.com/book/1
- 학부에서 수강했던 전공 수업 내용을 정리하는 포스팅입니다.
- 내용 중에서 오타 또는 잘못된 내용이 있을 시 지적해 주시기 바랍니다.
댓글