AJAX를 이해하기 위한 모든 요소를 한데 모아보았다.
웹개발 기법중 하나로, 자바스크립트를 이용해 XML 방식으로 서버와 비동기적으로 통신하는 "기법"을 말한다.
개발을 하다보면 화면 전환(refresh) 없이 CRUD(create, read, update, delete)를 처리를 해야하는 상황이 생긴다. 이때 AJAX
를 활용하여 비동기통신을 하면 위의 상황을 간편하게 해결할 수 있다.
HTTP를 사용해 페이지 리로드하는 경우, 전체 리소스를 다시 불러옴으로써 이미지, 스크립트 , 기타 코드등을 모두 재요청하는 등 불필요한 리소스 낭비가 발생하지만, 비동기식 방식을 이용할 경우 필요한 부분만 불러와 사용할 수 있다.
즉 AJAX
를 활용하면 필요한 데이터만을 웹서버에 요청해서 받은 후 클라이언트에서 데이터에 대한 처리를 할 수 있다!
AJAX를 활용하여 비동기적으로 통신하는 법을 알아보자.
출처 : 컴퓨터이야기(http://hieroglyph.tistory.com/13)
결과적으로 사용자 입장에서는 페이지 이동이 발생되지 않고 페이지 내부 변화만 일어나게 된다!
이렇게 AJAX
방식을 사용하게 되면, 웹서버에서 전적으로 처리되던 데이터 일부를 클라이언트에서도 처리하게되므로 웹브러우저(클라이언트)와 웹 서버 사이에 교환되는 데이터 량+웹서버 데이터 처리량이 모두 줄기 때문에 어플리케이션의 응답 반응도 보다 개선된다.
이러렇게 데이터 량과 데이터 처리량을 줄여 어플리케이션 환경을 개선할 수 있기에, 모던웹(페이스북, 구글)에서 많이 사용된다. (다른 페이지로 가는 버튼을 클릭해도 url은 바뀌지 않고 안의 html (예를 들면 댓글창이나 메일함)등이 바뀌는 경우 등)
비동기 처리를 위하여 ajax 사용 선언한다.
GET 방식인지, POST 방식인지 정한다.
클라이언트가 서버로 보낼 데이터를 만들어 보낸다
GET의 경우 전달할 데이터값이 있으면 보내야할 URL에 쿼리스트링 또는 data에 키와 밸류를 선언해서 보낸다.
POST의 경우 폼에 있는 데이터를 서버로 전송하기 위해서 formData와 serialize를 사용한다.
서버에서 클라이언트로 보내야할 dataType을 정한다.
// 필요한 데이터만 추출한다.
let param1 = $("#param1").val(); // 서버로 보내야할 데이터 1
let param2 = $("#param2").val(); // 서버로 보내야할 데이터 2
// 첫 번째 방식 : URL에 쿼리스트링 붙이기
$.ajax({ // 1. ajax 선언
url: `${CONTEXT_PATH}/xxx/aaa/edit?param1=${param1}¶m2=${param2}`, // 3. URL 쿼리스트링
method: 'GET', // 2. GET 방식 선언
async = true,
dataType: 'html', // 4. dataType 결정
success : function (res) {
// 서번단에서 HTML을 반환해서 기존 페이지를 깜빡임없이 새로 고친다.
document.querySelector("#appendHtml").innerHTML = res;
},
error: function (xhr) {
alert("fail");
}
});
// 두 번쨰 방식 : data에 키와 밸류 값으로 전달
$.ajax({ // 1. ajax 선언
url: `${CONTEXT_PATH}/xxx/aaa/edit`,
method: 'GET', // 2. GET 방식 선언
async : true,
data : { param1 : param1, param2 : param2 }, // 3. data에 key, value 전달
dataType : 'html', // 4. dataType 결정
success : function (res) {
// 서번단에서 HTML을 반환해서 기존 페이지를 깜빡임없이 새로 고친다.
document.querySelector("#appendHtml").innerHTML = res;
},
error: function (xhr) {
alert("fail");
}
});.
주의! ⚠️
클라이언트에서 서버로 쿼리스트링을 사용하여,
또는 데이터를 이용해서 등 전송하는 경우 키와 밸류 형태로 보내게 되는데,
키로 선언된 변수명은 커맨드 객체의 프로퍼티로 선언이 되어있어야 한다.
@Controller
@RequiredArgsConstructor
@RequestMapping("/xxx/aaa")
public class AjaxController {
private final XXXService = xxxService;
/**
* XXXVo 내부에는 param1과 param2라는 이름의 프로퍼티가 존재해야
* 클라이언트에서 키와 밸류로 보낸 데이터가 바인딩이 된다.
*/
@GetMapping("/edit")
public String edit(XXXVo xxxVo, Model model) {
xxxService.update(xxxVo);
model.addAttribute("result", xxxService.findxxxs(xxxVo));
return "html 페이지 리턴";
}
}
Ajax를 사용하여 POST 방식으로 form에 있는 데이터 값을 전부 가져오기 위해서는 크게 formData
, serializeObject
2가지 방식이 존재한다.
formData
는 폼을 그대로 submit한 효과가 있으며, serialize
는 폼에있는 name과 value를 이용하여 name=value 형태로 쿼리스트링(querystring)을 만들어준다.
⚠️ 주의
formData
나serialize
나 어떤것을 써도 서버단에 데이터를 보낼 수 있지만,formData
만 써야하는 상황이 있는데 바로 비동기로 파일 업로드를 하는 경우 이다. 그 이유는serialize
는 폼에 있는 input 데이터들을 긁어오면서 쿼리스트링*으로 변환하여 binary data*는 변환되지 않기 때문이다!
💡QueryString: 사용자가 입력 데이터를 전달하는 방법중의 하나로, url 주소에 미리 협의된 데이터를 파라미터를 통해 넘기는 것을 말한다.
예 ) http://host:port/path?querystring
query parameters(물음표 뒤에 = 로 연결된 key value pair 부분)을 url 뒤에 덧붙여서 추가적인 정보를 서버 측에 전달하는 것이다. 클라이언트가 어떤 특정 리소스에 접근하고 싶어하는지 정보를 담는다.
💡Binary Data : 이진 데이터. 기본 단위가 2개의 상태만 가지는 데이터이다.(0 or 1) 보통 문자가 아닌 data의 형태를 통칭한다
참고할만한 자료🤗
https://velog.io/@pear/Query-String-쿼리스트링이란
https://stackoverflow.com/questions/6314214/what-is-binary-data
POST 예제
function uploadFile() {
let formData = new FormData(document.getElementById('uploadForm'));
$.ajax({ // 1. ajax 선언
url: "/xxx/aaa/upload",
data: formData, // 3. formData로 설정
dataType: 'json', // 4. 데이터 타입 설정 (서버가 받으니까 json으로)
processData: false, // 비동기 파일 업로드시 꼭 설정해줘야 하는 속성
contentType: false, // 비동기 파일 업로드시 꼭 설정해줘야 하는 속성
type: 'POST', // 2. post 방식 선언
success: function (res) {
alert("success");
},error: function (xhr) {
alert(xhr.responseText);
}
});
}
장점
단점
XML은 HTML처럼 데이터를 보여주는 목적이 아닌, 데이터를 저장하고 전달할 목적으로만 만들어진 "언어"다.
같은 마크업 언어*인 HTML과 달리 웹상에서 구조화된 문서를 전송가능하도록 설계되었다.
💡마크업 언어: 태그 등을 이용하여 데이터의 구조를 기술하는 언어의 한 가지이다.
예를 들어 HTML에서는CPU 2.83GHz
라는 데이터를 표기할 때 어디부터가 데이터 명이고, 어디부터가 실제 데이터인지 표시할 수 있는 마땅한 방법이 없다.
이런 문제를 해결하기 위해 XML을 이용하면 데이터 이름, 실제 데이터, 데이터 단위를 구분하여 표현이 가능하다. 즉, 데이터에 의미를 부여하는 메타데이터*를 기술할 수 있다.
위의 예를 XML로 바꾸면 데이터 명은<dataname>CPU</dataname>
가 되고,
데이터 값은<datavalue>2.83</datavalue>
이 된다.
💡메타데이터 : 데이터에 관한 구조화된 데이터로, 다른 데이터를 설명해 주는 데이터.
원래는 웹에서 사용할 목적으로 만들었는데, 웹환경이 아닌 일반 TCP/IP 네트워크 통신을 할 때에도 점점 사용빈도가 늘어나고 있는 추세이다.
디지털 기반의 네트워크 통신을 할 때 송신자와 수신자간에서는 서로 주고받는 데이터 패킷을 비트 단위로 정확하게 맞춰줘야 문제가 생기지 않는데, 이 비트단위 데이터 통신에 하도 불확실성을 방지하고자 요즘은 XML로 데이터를 주고받는것이 추세화 되었다.
이렇게 하면 최소한 패킷 사이즈*가 안 맞아서 발생하는 버그는 줄일 수 있다. 그리고 이렇게 만든 프로그램은 XML로 데이터를 주고받기 때문에 웹확장성도 덤으로 갖게된다.
💡Packet : 데이터와 호 제어 신호가 포함된 2 진수, 즉 비트 그룹을 지칭한다.
패킷은 일반적으로 128 바이트가 표준이지만 52, 64, 256 옥텟 등 편의에 따라 크기를 바꿀 수 있으며, 옥텟은 보통 8 비트로 구성되고 이를 1 문자로 간주한다.
64자를 1 세그먼트로 하고, 128자를 1 패킷으로 하는 표준 패킷에 있어 그 관계는 다음과 같다.
1 packet = 2 segment = 128 octet = 1,024 bit
자바스크립트에서는 여러 모로 취급이 불편하고, 실제 데이터 양에 비해서 엄청난 덩치를 자랑한다.
이를 보완하기 위해 JSON이라는 포맷이 탄생하게 되었다 → 요즘은 JSON을 더 많이 사용한다!
문자열을 기반으로 하기에 실 데이터에 비해 오버헤드*가 많다.
메모리 상에 들어있던 데이터를 XML이나 JSON으로 변환하여 전송하고, 다시 이렇게 전송받은 XML 이나 JSON 데이터를 메모리에 복원시키기에 오버헤드가 크다.
네트워크 트래픽에 대해선 압축 전송으로 극복할 수 있지만 어쨌든 받은 뒤에는 그 압축을 풀어야 하니까 근본적인 문제는 해결되지 않는다.
어쩌다 한 번 이러한 방식으로 동작하는 프로그램을 운용하는 경우에는 별 문제가 없지만, 1초에도 수십 번 이상 이러한 요청을 받아서 처리하여 결과를 돌려주는 서비스를 운용할 때에는 상당한 문제가 된다.
💡오버헤드 : 어떤 명령어를 처리하는데 소비되는 간접적, 추가적인 처리 시간 및 메모리 등을 지칭한다
비동기통신을 담당하는 자바스크립트 객체이다.
서버에 데이터를 요청하여 그 결과를 받아오며, 페이지 전체를 받지 않고도 특정 URL로부터 페이지 일부에만 필요한 데이터를 수신하는 역할을 한다.
DOM 조작도 가능하여, 응답 결과 데이터에 따라 웹페이지 내에 삽입/변경 하기도 한다.
XMLHttpRequest
객체를 생성한다
var xhr = new XMLHttpRequest();
서버와의 처리 방법을 등록한다
// open() : 요청을 초기화
xhr.open(method, url);
응답 시, 이에 반응/처리해야 할 이벤트 핸들러를 작성한다
xhr.onreadystatechange = function() { ... };
필요 시, 요청 헤더를 설정한다
// 예시 : setRequestHeader 메소드에 의한 Content-Type 설정
xhr.setRequestHeader("Content-Type","text/plain");
요청을 전송하고, 통신을 시작한다
// send() : 요청 전송 및 통신 시작
xhr.send(공백 또는 null 또는 data);
var xhr = new XMLHttpRequest(); // 1. 객체 생성
xhr.open('GET','http://www.ktword.co.kr/ajax_test'); // 2. 서버와의 처리 방법 등록
xhr.onreadystatechange = function() { // 3. 응답에 따른 반응 처리 방법 기재
if (xhr.readyState === 4) { // (수신 완료, XMLHttpRequest.DONE : 4)
if (xhr.status === 200) { // (통신 성공)
console.log(xhr.responseText);
} else {
console.log('서버 에러 발생');
}
} else { // 통신 완료 전
console.log('통신중...');
}
}
xhr.send(); // 5. 요청 전송, 통신 시작
서버에서 클라이언트로 데이터를 보낼 때 사용하는 양식.
클라이언트가 사용하는 언어에 관계 없이 통일된 데이터를 주고받을 수 있도록, 일정한 패턴을 지닌 문자열을 생성해 내보내면 클라이언트는 그를 해석해 데이터를 자기만의 방식으로 온전히 저장, 표시할 수 있게 된다.
과거 웹 초기 시절부터 사용되어 온 XML은 헤더와 태그 등의 여러 요소로 가독성이 떨어지고, 쓸데없이 용량을 잡아먹는다는 단점이 항상 지적되어 왔다.
반면 JSON은 간결하고 통일된 양식을 사용해 사람과 기계 모두 이해하기 쉬우며 용량이 작아 각광을 받고 있다.
문법 오류에 민감하다
콤마가 누락되거나 중괄호가 잘못 닫히는 등 구두점에서 오타가 나면 전체 JSON파일이 망가진다. 찾기 기능이 없는 편집기에서 줄 길이가 길어지면 콤마가 누락된 곳을 찾기 힘들다.
주석을 지원하지 않는다.
그래서 설정 파일을 JSON으로 작성하는 것은 어렵다.
데이터 타입을 강제할 수 없다.
JSON 스키마로 보완은 가능하지만 데이터 스스로 자신의 타입을 기술할 방법이 없다.
{
"employees": [
{
"name": "Surim",
"lastName": "Son"
},
{
"name": "Someone",
"lastName": "Huh"
},
{
"name": "Someone else",
"lastName": "Kim"
}
]
}
JSON을 가져오기 위해서는, XMLHttpRequest
(XHR)를 사용하면 된다.
변수로 둘 JSON의 URL을 가져온다.
var requestURL = 'https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json';
요청을 만들기 위해, new
키워드를 이용하여 XMLHttpRequest
생성자로부터 새로운 request 인스턴스를 생성해야 한다.
var request = new XMLHttpRequest();
이제 open()
메소드를 사용해 새로운 요청을 만든다.
request.open('GET', requestURL);
open()
메소드는 최소 두 개의 매개변수를 가진다.
responseType
을 JSON으로 설정한다.
-> 이를 통해 XHR에게 서버가 JSON 데이터를 반환할 것이며, 자바스크립트 객체로서 변환될 것이라는 걸 알린다.
send()
메서드를 이용해 요청을 전송한다.
request.responseType = 'json';
request.send();
서버의 응답을 처리하는 코드를 작성한다.
request.onload = function() {
var superHeroes = request.response;
// superHeroes에 요청에 대한 응답 저장
// JSON데이터에 기반한 자바스크립트 object 포함
populateHeader(superHeroes);
showHeroes(superHeroes);
}
responseType을 json
으로 설정할 경우, 서버의 응답이 json
으로 넘어오는데, 가끔 그 응답이 날것 그대로의 json
문자열로 넘어와 사용자가 직접 객체로 변환시켜줘야 하는 경우가 있다. 또한, 네트워크를 통해 자바스크립트 객체를 전송하고 싶을 때도 전송 전에 그걸 json
문자열로 변환시켜줘야 한다.
이 때 대표적으로 사용되는 메소드가 parse()
, stringify()
이다.
예제
//parse()
request.open('GET', requestURL);
request.responseType = 'text'; // 서버로부터 응답을 text형태로 받는다
request.send();
request.onload = function() {
var superHeroesText = request.response; // response를 string형태로 받아온다
var superHeroes = JSON.parse(superHeroesText); // 받아온 string을 javascript object로 변환한다
populateHeader(superHeroes);
showHeroes(superHeroes);
}
//stringify()
var myJSON = { "name": "Chris", "age": "38" };
myJSON
var myString = JSON.stringify(myJSON); // myJSON이라는 object를 string형태로 변경한다
myString
GET 은 클라이언트에서 서버로 어떠한 리소스로 부터 정보를 요청하기 위해 사용되는 메서드이다.
(예 : 게시판의 게시물을 조회할 때 사용)
GET을 통한 요청은 URL 주소 끝에 파라미터로 포함되어 전송되며, 이 부분을 쿼리 스트링 (QueryString) 이라고 부른다.
URL 끝에 ?
를 붙이고 그다음 변수명1=값1&변수명2=값2...
형식으로 이어 붙이면 된다.
예)
www.example.com/show?name1=value1&name2=value2
서버에서는 name1
과 name2
라는 파라미터 명으로 각각 value1
과 value2
의 파라미터 값을 전달 받을 수 있다.
GET 요청은 캐시가 가능하다.
GET을 통해 서버에 리소스를 요청할 때 웹 캐시가 요청을 가로채 서버로부터 리소스를 다시 다운로드하는 대신, 리소스의 복사본을 반환한다.
HTTP 헤더에서 cache-control 헤더를 통해 캐시 옵션을 지정할 수 있다.
GET 요청은 브라우저 히스토리에 남는다.
GET 요청은 북마크 될 수 있다.
GET 요청은 길이 제한이 있다.
GET 요청의 길이 제한은 표준이 따로 있는건 아니고 브라우저마다 제한이 다르다.
GET 요청은 중요한 정보를 다루면 안된다(보안)⭐️
GET 요청은 파라미터에 내용이 다 노출되어 버리기 때문에 유의해야 한다.
GET은 데이터를 요청할때만 사용 된다.
POST는 클라이언트에서 서버로 리소스를 생성하거나 업데이트하기 위해 데이터를 보낼 때 사용 되는 메서드로, 게시판에 게시글을 작성하는 작업 등을 할 때 사용할 된다.
POST는 전송할 데이터를 HTTP 메시지 body 부분에 담아서 서버로 보낸다. GET에서 URL 의 파라미터로 보냈던 name1=value1&name2=value2
가 body에 담겨 보내진다 생각하면 된다.
(body 의 타입은 Content-Type 헤더에 따라 결정 된다.)
보통 길이 제한이 따로 없어 용량이 큰 데이터를 보낼 때 사용하거나, 데이터가 외부적으로 드러나지 않아 보안이 필요한 부분에 많이 사용된다.
(하지만 데이터를 암호화하지 않으면 body의 데이터도 결국 볼 수 있는건 똑같다.)
POST를 통한 데이터 전송은 보통 HTML form 을 통해 서버로 전송된다.
사용목적 : GET은 서버의 리소스에서 데이터를 요청할 때, POST는 서버의 리소스를 새로 생성하거나 업데이트할 때 사용한다.
DB로 따지면 GET은 SELECT 에 가깝고, POST는 Create 에 가깝다고 보면 된다.
요청에 body 유무 : GET 은 URL 파라미터에 요청하는 데이터를 담아 보내기 때문에 HTTP 메시지에 body가 없다. POST 는 body 에 데이터를 담아 보내기 때문에 당연히 HTTP 메시지에 body가 존재한다.
멱등성 (idempotent) : GET 요청은 멱등이며, POST는 멱등이 아니다.
GET은 리소스를 조회한다는 점에서 여러 번 요청하더라도 응답이 똑같을 것이다.
반대로 POST는 리소스를 새로 생성하거나 업데이트할 때 사용되기 때문에 멱등이 아니라고 볼 수 있다. (POST 요청이 발생하면 서버가 변경될 수 있다.)
💡멱등 : 연산을 여러 번 적용하더라도 결과가 달라지지 않는 성질을 의미한다.
기억해뒀다가 공부 후에 다시 읽어봐야겠어요!! 깔끔한 정리 👍