펌글 - 출처: https://ko.javascript.info/xmlhttprequest#ref-570
XMLHttpRequest란?
XMLHttpRequestJavaScript에서 HTTP 요청을 만들 수 있는 내장 브라우저 개체입니다.
현재 대부분의 주요 웹 브라우저는 서버에 데이터를 요청하기 위한 XMLHttpRequest 객체를 내장하고 있습니다.
XMLHttpRequest 객체는 서버로부터 XML 데이터를 전송받아 처리하는 데 사용됩니다. 이 객체를 사용하면
웹 페이지가 전부 로딩된 후에도 서버에 데이터를 요청하거나 서버로부터 데이터를 전송받을 수 있습니다.
즉, 웹 페이지 전체를 다시 로딩하지 않고 일부분만을 갱신할 수 있게 됩니다.
fetch라는 현대적인 방법도있으나, 현대 웹 개발에서 XMLHttpRequest세 가지 이유로 사용됩니다.
- 역사적 이유: XMLHttpRequest.
- 우리는 오래된 브라우저를 지원해야 하며 pollyfills(예: 스크립트를 작게 유지하기 위해)을 원하지 않을때,
- fetch가 아직 할 수 없는 것이 필요할때. (예를 들어 업로드 진행 상황을 추적하는 것)
기본사항
XMLHttpRequest에는 동기 및 비동기의 두 가지 작업 모드가 있습니다.
대부분의 경우에 사용되는 비동기식을 먼저 살펴보겠습니다.
요청을 수행하려면 3단계가 필요합니다.
1.XMLHttpRequest 생성
let xhr = new XMLHttpRequest();
2.일반적으로 new XMLHttpRequest 직후에 초기화합니다.
xhr.open(method, URL, [async, user, password])
이 메소드는 요청의 기본 매개변수를 지정합니다.
method – HTTP 방법. 일반적으로 "GET" 또는 "POST".
URL – 요청할 URL, 문자열, URL 개체일 수 있습니다.
async – 명시적으로 false로 설정하면 요청이 동기적
user, password – 기본 HTTP 인증을 위한 로그인 및 비밀번호(필요한 경우).
3.요청 보내기
xhr.send([body])
이 메서드는 연결을 열고 서버에 요청을 보냅니다. 선택적 body 매개변수에는 요청 본문이 포함됩니다.
GET과 같은 일부 요청 메서드에는 body가 없습니다. POST와 같은 일부는 body를 사용하여 데이터를 서버로 보냅니다.
4.응답을 위해 이벤트를 수신합니다
다음 세 가지 이벤트가 가장 널리 사용됩니다.
- load– 요청이 완료되고(HTTP 상태가 400 또는 500과 같은 경우에도) 응답이 완전히 다운로드된 경우.
- error– 요청을 할 수 없는 경우(예: 네트워크 다운 또는 유효하지 않은 URL).
- progress– 응답이 다운로드되는 동안 주기적으로 트리거되며 다운로드된 양을 보고합니다.
xhr.onload = function() {
alert(`Loaded: ${xhr.status} ${xhr.response}`);
};
xhr.onerror = function() { // 요청을 전혀 할 수 없는 경우에만 트리거됩니다.
alert(`Network Error`);
};
xhr.onprogress = function(event) { //주기적으로 트리거
// event.loaded - 다운로드된 바이트 수
// event.lengthComputable = 서버가 Content-Length 헤더를 보낸 경우 true
// event.total - 총 바이트 수(lengthComputable인 경우)
alert(`Received ${event.loaded} of ${event.total}`);
};
다음은 전체 예입니다.
아래 코드는 서버에서 /article/xmlhttprequest/example/load의 URL을 로드하고 진행 상황을 인쇄합니다.
// 1. 새 XMLHttpRequest 개체 만들기
let xhr = new XMLHttpRequest();
// 2. 구성하다: URL에 대한 GET 요청
xhr.open('GET', '/article/xmlhttprequest/example/load');
// 3. 네트워크를 통해 요청 보내기
xhr.send();
// 4. 응답을 받은 후 호출됩니다.
xhr.onload = function() {
if (xhr.status != 200) { // analyze HTTP status of the response
alert(`Error ${xhr.status}: ${xhr.statusText}`); // e.g. 404: Not Found
} else { // show the result
alert(`Done, got ${xhr.response.length} bytes`); // response is the server
}
};
xhr.onprogress = function(event) {
if (event.lengthComputable) {
alert(`Received ${event.loaded} of ${event.total} bytes`);
} else {
alert(`Received ${event.loaded} bytes`); // no Content-Length
}
};
xhr.onerror = function() {
alert("Request failed");
};
서버가 응답하면 다음 xhr속성에서 결과를 받을 수 있습니다.
status
HTTP 상태 코드(숫자) : status 프로퍼티는 서버의 문서 상태를 나타냅니다.
- 200 : 서버에 문서가 존재함.
- 404 : 서버에 문서가 존재하지 않음.
statusText
HTTP 상태 메시지(문자열) : 일반적으로 200은 OK, 404는 Not Found, 403은 Forbidden 등입니다.
response
(이전 스크립트는 responseText를 사용할 수 있음)
서버 응답 본문입니다.
해당 속성을 사용하여 시간 제한을 지정할 수도 있습니다.
xhr.timeout = 10000; // timeout in ms, 10 seconds
요청이 주어진 시간 내에 성공하지 못하면 취소되고 timeout이벤트가 트리거됩니다.
URL 검색 매개변수
URL에 ?name=value와 같은 매개변수를 추가하고
적절한 인코딩을 보장하기 위해 URL 객체를 사용할 수 있습니다.
let url = new URL('https://google.com/search'); url.searchParams.set('q', 'test me!'); // 매개변수 'q'가 인코딩됨 xhr.open('GET', url); // https://google.com/search?q=test+me%21
responseType
xhr.responseType 속성을 사용하여 응답 형식을 설정할 수 있습니다.
""(기본값) – 문자열로 가져오기,
"text" – 문자열로 가져오기,
"arraybuffer" – ArrayBuffer로 가져옵니다(이진 데이터의 경우 ArrayBuffer, 이진 배열 장 참조).
"blob" – Blob으로 가져오기(바이너리 데이터의 경우 Blob 장 참조),
"document" – XML 문서로 가져오기(XPath 및 기타 XML 메서드 사용 가능),
"json" – JSON으로 가져옵니다(자동으로 구문 분석됨).
예를 들어 응답을 JSON으로 받겠습니다.
let xhr = new XMLHttpRequest();
xhr.open('GET', '/article/xmlhttprequest/example/json');
xhr.responseType = 'json';
xhr.send();
// 응답 {"message": "Hello, world!"}
xhr.onload = function() {
let responseObj = xhr.response;
alert(responseObj.message); // Hello, world!
};
readyStates 프로퍼티 확인 - onreadystatechage
readyState 프로퍼티는 XMLHttpRequest 객체의 현재 상태를 나타냅니다.
이 프로퍼티의 값은 객체의 현재 상태에 따라 다음과 같은 주기로 변화합니다.
UNSENT (숫자 0) : XMLHttpRequest 객체가 생성됨.
OPENED (숫자 1) : open() 메소드가 성공적으로 실행됨.
HEADERS_RECEIVED (숫자 2) : 모든 요청에 대한 응답이 도착함.
LOADING (숫자 3) : 요청한 데이터를 처리 중임.
DONE (숫자 4) : 요청한 데이터의 처리가 완료되어 응답할 준비가 완료됨.
XMLHttpRequest 개체는 0 → 1 → 2 → 3 → … → 3 → 4의 순서로 이동합니다.
상태 3은 네트워크를 통해 데이터 패킷이 수신될 때마다 반복됩니다.
readystatechange 이벤트를 사용하여 추적할 수 있습니다.
xhr.onreadystatechange = function() {
if (xhr.readyState == 3) {
// loading
}
if (xhr.readyState == 4) {
// request finished
}
};
정말 오래된 코드에서 readystatechange 리스너를 찾을 수 있습니다. 로드 및 기타 이벤트가 없었던 시간이 있었기 때문에 역사적인 이유로 거기에 있습니다. 요즘에는 로드/오류/진행 처리기에서 더 이상 사용되지 않습니다.
요청중단 abort()
언제든지 요청을 종료할 수 있습니다. 에 대한 호출은 xhr.abort()다음을 수행합니다.
xhr.abort(); // terminate the request
그러면 중단 이벤트가 트리거되고 xhr.status는 0이 됩니다.
동기적요청 async = false
open 메서드에서 세 번째 매개변수 async가 false로 설정되면 요청이 동기적으로 이루어집니다.
즉, JavaScript 실행은 send()에서 일시 중지되고 응답이 수신되면 다시 시작됩니다. 경고 또는 프롬프트 명령과 비슷합니다.
다음은 재작성된 예입니다. open의 세 번째 매개변수는 false입니다.
let xhr = new XMLHttpRequest();
xhr.open('GET', '/article/xmlhttprequest/hello.txt', false);
try {
xhr.send();
if (xhr.status != 200) {
alert(`Error ${xhr.status}: ${xhr.statusText}`);
} else {
alert(xhr.response);
}
} catch(err) { // instead of onerror
alert("Request failed");
}
좋아 보일 수 있지만 동기식 호출은 로딩이 완료될 때까지 페이지 내 JavaScript를 차단하기 때문에 거의 사용되지 않습니다. 일부 브라우저에서는 스크롤이 불가능해집니다. 동기식 호출에 너무 많은 시간이 걸리면 브라우저에서 "멈춘" 웹 페이지를 닫으라고 제안할 수 있습니다.
다른 도메인에서 요청하거나 제한 시간을 지정하는 것과 같은 XMLHttpRequest의 많은 고급 기능은 동기식 요청에 사용할 수 없습니다. 또한 보시다시피 진행률 표시가 없습니다.
이 때문에 동기식 요청은 거의 사용되지 않습니다.
HTTP-headers
XMLHttpRequest를 사용하면 사용자 지정 헤더를 보내고 응답에서 헤더를 읽을 수 있습니다.
HTTP 헤더에는 3가지 방법이 있습니다.
setRequestHeader(이름, 값)
주어진 이름과 값으로 요청 헤더를 설정합니다.
xhr.setRequestHeader('Content-Type', 'application/json');
getResponseHeader(이름)
지정된 이름의 응답 헤더를 가져옵니다(Set-Cookie 및 Set-Cookie2 제외).
xhr.getResponseHeader('Content-Type')
getAllResponseHeaders()
Set-Cookie 및 Set-Cookie2를 제외한 모든 응답 헤더를 반환합니다.
헤더는 다음과 같이 한 줄로 반환됩니다.
Cache-Control: max-age=31536000
Content-Length: 4260
Content-Type: image/png
Date: Sat, 08 Sep 2012 16:53:16 GMT
헤더 사이의 줄 바꿈은 항상 "\r\n"(OS에 의존하지 않음)이므로 개별 헤더로 쉽게 분할할 수 있습니다. 이름과 값 사이의 구분 기호는 항상 콜론 뒤에 공백 ":"이 옵니다. 그것은 사양에 고정되어 있습니다.
따라서 이름/값 쌍이 있는 객체를 얻으려면 약간의 JS를 추가해야 합니다.
이와 같이(두 헤더의 이름이 같은 경우 후자가 전자를 덮어쓴다고 가정):
let headers = xhr
.getAllResponseHeaders()
.split('\r\n')
.reduce((result, current) => {
let [name, value] = current.split(': ');
result[name] = value;
return result;
}, {});
// headers['Content-Type'] = 'image/png'
POST, FormData
POST 요청을 만들면 내장 FormData 객체를 사용할 수 있습니다.
et formData = new FormData([form]); // 객체 생성, 선택적으로 <form>에서 채우기
formData.append(name, value); // 필드를 추가합니다
우리는 그것을 생성하고 선택적으로 양식에서 채우고 필요한 경우 더 많은 필드를 추가한 다음 다음을 수행합니다.
xhr.open('POST', ...) – POST 메서드를 사용합니다.
xhr.send(formData) 양식을 서버에 제출합니다.
<form name="person">
<input name="name" value="John">
<input name="surname" value="Smith">
</form>
<script>
let formData = new FormData(document.forms.person);
formData.append("middle", "Lee");
let xhr = new XMLHttpRequest();
xhr.open("POST", "/article/xmlhttprequest/post/user");
xhr.send(formData);
xhr.onload = () => alert(xhr.response);
</script>
양식은 multipart/form-data 인코딩으로 전송됩니다.
또는 JSON이 더 마음에 들면 JSON.stringify하여 문자열로 보냅니다.
Content-Type: application/json 헤더를 설정하는 것을 잊지 마세요.
많은 서버 측 프레임워크는 JSON을 자동으로 디코딩합니다.
let xhr = new XMLHttpRequest();
let json = JSON.stringify({
name: "John",
surname: "Smith"
});
xhr.open("POST", '/submit')
xhr.setRequestHeader('Content-type', 'application/json; charset=utf-8');
xhr.send(json);
FormData 설명 링크 : https://rebornbb.tistory.com/entry/JS-FormData-%EC%84%A4%EB%AA%85-%EC%A0%95%EB%A6%AC
upload.onprogress
진행률 이벤트는 다운로드 단계에서만 트리거됩니다.
즉, 무언가를 POST하면 XMLHttpRequest는 먼저 데이터(요청 본문)를 업로드한 다음 응답을 다운로드합니다.
loadstart – 업로드가 시작되었습니다.
progress – 업로드 중에 주기적으로 트리거됩니다.
abort – 업로드가 중단되었습니다.
error – HTTP가 아닌 오류입니다.
load – 업로드가 성공적으로 완료되었습니다.
timeout – 업로드 시간이 초과되었습니다(timeout 속성이 설정된 경우).
loadend – 업로드가 성공 또는 오류로 완료되었습니다.
핸들러의 예:
xhr.upload.onprogress = function(event) {
alert(`Uploaded ${event.loaded} of ${event.total} bytes`);
};
xhr.upload.onload = function() {
alert(`Upload finished successfully.`);
};
xhr.upload.onerror = function() {
alert(`Error during the upload: ${xhr.status}`);
};
다음은 실제 예입니다. 진행률 표시가 있는 파일 업로드:
<input type="file" onchange="upload(this.files[0])">
<script>
function upload(file) {
let xhr = new XMLHttpRequest();
// track upload progress
xhr.upload.onprogress = function(event) {
console.log(`Uploaded ${event.loaded} of ${event.total}`);
};
// track completion: both successful or not
xhr.onloadend = function() {
if (xhr.status == 200) {
console.log("success");
} else {
console.log("error " + this.status);
}
};
xhr.open("POST", "/article/xmlhttprequest/post/upload");
xhr.send(file);
}
</script>
Cross-origin request
XMLHttpRequest는 가져오기와 동일한 CORS 정책을 사용하여 출처 간 요청을 할 수 있습니다.
가져오기와 마찬가지로 기본적으로 쿠키와 HTTP 인증을 다른 원본으로 보내지 않습니다. 활성화하려면 xhr.withCredentials를 true로 설정합니다.
let xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.open('POST', 'http://anywhere.com/request');
...
최종요약
GET 요청의 일반적인 코드 XMLHttpRequest
let xhr = new XMLHttpRequest();
xhr.open('GET', '/my/url');
xhr.send();
xhr.onload = function() {
if (xhr.status != 200) { // HTTP error
// handle error
alert( 'Error: ' + xhr.status);
return;
}
// get the response from xhr.response
};
xhr.onprogress = function(event) {
// report progress
alert(`Loaded ${event.loaded} of ${event.total}`);
};
xhr.onerror = function() {
// handle non-HTTP error (e.g. network down)
};
- loadstart– 요청이 시작되었습니다.
- progress– 응응답의 데이터 패킷이 도착했으며 현재 전체 응답 본문이 응답 중입니다.
- abort– 요청이 xhr.abort() 호출에 의해 취소되었습니다.
- error– 연결 오류가 발생했습니다. (예:잘못된 도메인 이름) 404와 같은 HTTP 오류에는 발생하지 않습니다.
- load– 요청이 성공적으로 완료되었습니다.
- timeout– 시간 초과로 인해 요청이 취소되었습니다(설정된 경우에만 발생).
- loadend– load, error, timeout또는 이후에 트리거합니다 abort.
+ Jquery를 사용한 코드
var serverAddress = 'https://localhost:3000';
// jQuery의 .get 메소드 사용
$.ajax({
url: serverAddress,
type: 'GET',
success: function onData (data) {
console.log(data);
},
error: function onError (error) {
console.error(error);
}
});
'STUDY > JavaScript' 카테고리의 다른 글
[JS] wss와 ws 차이점 (0) | 2023.05.04 |
---|---|
[JS] 스크롤바 맨 아래로 내리기 (0) | 2023.04.27 |
[JS] URL생성자 기초 정리 (0) | 2023.04.12 |
[JS] Web Audio API (0) | 2023.04.03 |
[JS] Media Stream API (0) | 2023.04.03 |