AJAX và đối tượng XMLHttpRequest trong JavaScript

Javascript nâng cao | by Học Javascript

AJAX không phải là một công nghệ đơn lẻ mà là sự kết hợp của nhiều công cụ, trong đó đối tượng XMLHttpRequest đóng vai trò nền tảng giúp JavaScript có thể giao tiếp với máy chủ một cách bất đồng bộ. Nhờ vào XMLHttpRequest, các website có thể gửi và nhận dữ liệu trong nền, giúp cập nhật nội dung ngay lập tức mà không làm gián đoạn người dùng.

Trong bài viết này, mình sẽ cùng tìm hiểu chi tiết về AJAX, cách hoạt động của XMLHttpRequest, cú pháp, ví dụ minh họa cũng như các ứng dụng thực tế phổ biến trong phát triển web.

AJAX là gì?

AJAX là viết tắt của Asynchronous JavaScript and XML, là một kỹ thuật được sử dụng trong phát triển web để gửi và nhận dữ liệu từ máy chủ một cách bất đồng bộ, nghĩa là không cần tải lại toàn bộ trang web. Điều này giúp nâng cao trải nghiệm người dùng, làm cho các ứng dụng web trở nên mượt mà, nhanh nhạy và hiện đại hơn.

AJAX không phải là một công nghệ riêng biệt

Thay vì là một ngôn ngữ hay framework độc lập, AJAX là sự kết hợp của nhiều công nghệ web hoạt động cùng nhau:

  • HTML/CSS: dùng để tạo giao diện và trình bày nội dung.

  • JavaScript: xử lý các sự kiện của người dùng (như click, nhập liệu...), thực hiện logic gửi và nhận dữ liệu.

  • XMLHttpRequest (hoặc hiện nay có thể thay thế bằng Fetch API): là công cụ giúp gửi request và nhận response từ server.

  • JSON hoặc XML: là định dạng dữ liệu được sử dụng để trao đổi giữa client và server.

Cơ chế hoạt động nổi bật của AJAX

AJAX cho phép cập nhật một phần nội dung của trang web, mà không cần reload toàn bộ. Ví dụ: khi bạn gõ tìm kiếm trên Google và kết quả hiện ra ngay lập tức, đó chính là AJAX đang hoạt động.

Ưu điểm chính của AJAX

  • Giao tiếp bất đồng bộ: Gửi yêu cầu và tiếp tục xử lý các tác vụ khác trong khi chờ phản hồi từ server.

  • Tải nội dung nhanh hơn: Chỉ cần cập nhật phần cần thiết thay vì tải lại toàn trang.

  • Cải thiện trải nghiệm người dùng: Mọi thao tác diễn ra mượt mà, không bị gián đoạn.

  • Giảm tải cho server: Do không phải truyền lại toàn bộ nội dung trang mỗi khi có tương tác.

Đối tượng XMLHttpRequest là gì?

XMLHttpRequest (XHR) là một đối tượng do trình duyệt cung cấp, cho phép JavaScript gửi yêu cầu HTTP/HTTPS đến máy chủ và nhận phản hồi mà không cần tải lại trang. Đây chính là nền tảng cốt lõi giúp kỹ thuật AJAX hoạt động, đặc biệt là trong giai đoạn trước khi Fetch API được giới thiệu.

Tính năng chính của XMLHttpRequest

  • Gửi yêu cầu đến máy chủ một cách bất đồng bộ hoặc đồng bộ (mặc dù bất đồng bộ được khuyến khích sử dụng).

  • Hỗ trợ nhiều phương thức HTTP như:

    • GET: lấy dữ liệu.

    • POST: gửi dữ liệu (thường dùng cho form).

    • PUT, DELETE: thường dùng trong RESTful API.

  • Nhận dữ liệu phản hồi từ server dưới dạng văn bản (text), XML, hoặc JSON (tuỳ cách xử lý).

  • Có thể thiết lập các header tùy chỉnh trong request.

  • Cho phép theo dõi trạng thái của request thông qua thuộc tính readyState.


Ứng dụng phổ biến

  • Tìm kiếm gợi ý theo thời gian thực (autocomplete).

  • Tải thêm bình luận, bài viết, sản phẩm khi người dùng cuộn xuống.

  • Gửi form đăng nhập, đăng ký mà không cần tải lại trang.

  • Tự động cập nhật dữ liệu bảng điều khiển (dashboard).


Vì sao XMLHttpRequest vẫn quan trọng?

Mặc dù Fetch API đã thay thế dần trong các dự án mới vì cú pháp hiện đại hơn và hỗ trợ Promise, XMLHttpRequest vẫn rất phổ biến vì:

  • Được hỗ trợ bởi tất cả các trình duyệt, kể cả các trình duyệt cũ.

  • Một số thư viện JavaScript lớn (ví dụ jQuery) vẫn sử dụng XMLHttpRequest bên trong.

  • Cho phép kiểm soát chi tiết hơn về trạng thái kết nối, theo dõi tiến độ tải (upload/download), v.v.

IV. Các bước sử dụng XMLHttpRequest

Để thực hiện một yêu cầu HTTP bất đồng bộ với XMLHttpRequest, bạn cần thực hiện theo các bước cơ bản sau:


1. Tạo đối tượng XMLHttpRequest

Đầu tiên, bạn cần khởi tạo một đối tượng XMLHttpRequest:

const xhr = new XMLHttpRequest();

Đây là bước tạo một thể hiện (instance) của công cụ giúp JavaScript giao tiếp với server.


2. Cấu hình yêu cầu với .open()

Sử dụng phương thức .open() để cấu hình loại yêu cầu, URL và chế độ đồng bộ/bất đồng bộ:

xhr.open("GET", "https://api.example.com/data", true);
  • "GET": phương thức HTTP (có thể là "POST", "PUT", "DELETE"…).

  • "https://api.example.com/data": URL của tài nguyên cần lấy hoặc gửi dữ liệu đến.

  • true: chỉ định đây là yêu cầu bất đồng bộ (giá trị mặc định nên luôn dùng).


3. Xử lý phản hồi từ server

Sau khi gửi yêu cầu, bạn cần xử lý dữ liệu phản hồi bằng một trong hai cách phổ biến:

a. Sử dụng onreadystatechange:
xhr.onreadystatechange = function () {
  if (xhr.readyState === 4 && xhr.status === 200) {
    console.log("Dữ liệu nhận được:", xhr.responseText);
  }
};
  • readyState === 4: yêu cầu đã hoàn tất.

  • status === 200: phản hồi thành công từ server.

b. Hoặc dùng onload (cách đơn giản hơn):
xhr.onload = function () {
  if (xhr.status === 200) {
    console.log("Phản hồi thành công:", xhr.responseText);
  } else {
    console.error("Lỗi từ server:", xhr.statusText);
  }
};

4. Gửi yêu cầu với .send()

Sau khi đã cấu hình xong, bạn gửi yêu cầu:

xhr.send();
  • Với GET, bạn không cần tham số trong .send().

Với POST, bạn có thể truyền dữ liệu dạng JSON hoặc form:

xhr.setRequestHeader("Content-Type", "application/json");
xhr.send(JSON.stringify({ username: "admin", password: "1234" }));
const xhr = new XMLHttpRequest();
xhr.open("GET", "https://api.example.com/data", true);
xhr.onload = function () {
  if (xhr.status === 200) {
    console.log("Dữ liệu:", xhr.responseText);
  }
};
xhr.send();

V. Các thuộc tính và phương thức quan trọng trong XMLHttpRequest

Khi làm việc với XMLHttpRequest, bạn sẽ thường xuyên sử dụng các phương thức và thuộc tính sau để gửi yêu cầu HTTP, kiểm tra trạng thái phản hồi, và xử lý dữ liệu từ server.


1. xhr.open(method, url, async)

Dùng để cấu hình một yêu cầu HTTP trước khi gửi đi.

xhr.open("GET", "https://api.example.com/data", true);
  • method: Phương thức HTTP (ví dụ: "GET", "POST", "PUT", "DELETE"...).

  • url: Địa chỉ API hoặc tài nguyên muốn truy cập.

  • async: true cho phép xử lý bất đồng bộ (khuyên dùng), false cho đồng bộ (có thể làm treo trình duyệt).


2. xhr.send([body])

Dùng để gửi yêu cầu đến server sau khi đã cấu hình bằng .open().

xhr.send(); // Đối với GET

3. xhr.setRequestHeader(name, value)

Dùng để thiết lập tiêu đề (header) cho yêu cầu HTTP, ví dụ như kiểu dữ liệu gửi đi:

xhr.setRequestHeader("Content-Type", "application/json");

Lưu ý: Chỉ sử dụng sau khi xhr.open() và trước xhr.send().


✅ 4. xhr.readyState

Thuộc tính này cho biết trạng thái hiện tại của yêu cầu. Có 5 giá trị:

Giá trị Ý nghĩa
0 UNSENT – Chưa gọi .open()
1 OPENED – Đã gọi .open()
2 HEADERS_RECEIVED – Đã nhận header từ server
3 LOADING – Đang tải dữ liệu
4 DONE – Yêu cầu đã hoàn tất

Ví dụ:

xhr.onreadystatechange = function () {
  if (xhr.readyState === 4) {
    // xử lý dữ liệu
  }
};

5. xhr.statusxhr.statusText

  • xhr.status: Mã phản hồi HTTP (ví dụ: 200, 404, 500...).

  • xhr.statusText: Chuỗi mô tả mã trạng thái (ví dụ: "OK", "Not Found"...).

if (xhr.status === 200) {
  console.log("Thành công!");
} else {
  console.log("Lỗi:", xhr.statusText);
}

6. xhr.responseTextxhr.responseXML

  • xhr.responseText: Dữ liệu phản hồi dạng chuỗi văn bản (thường là JSON).

const jsonData = JSON.parse(xhr.responseText);

xhr.responseXML: Dữ liệu phản hồi nếu server trả về XML, sẽ được phân tích cú pháp thành tài liệu DOM.

const xmlDoc = xhr.responseXML;

VI. Ví dụ minh họa cơ bản

Để hiểu rõ cách hoạt động của XMLHttpRequest, ta sẽ xem qua ba ví dụ thực tế: gửi yêu cầu GET, gửi yêu cầu POST với dữ liệu JSON, và xử lý lỗi khi server trả về lỗi.


1. Gửi GET request và hiển thị kết quả

Mục tiêu: Gửi yêu cầu GET đến một API giả lập, sau đó hiển thị dữ liệu trên console.

const xhr = new XMLHttpRequest();
xhr.open("GET", "https://jsonplaceholder.typicode.com/posts/1", true);

xhr.onload = function () {
  if (xhr.status === 200) {
    const data = JSON.parse(xhr.responseText);
    console.log("Dữ liệu nhận được:", data);
  } else {
    console.error("Lỗi khi tải dữ liệu:", xhr.status);
  }
};

xhr.onerror = function () {
  console.error("Lỗi kết nối mạng.");
};

xhr.send();

Giải thích:

  • Gửi yêu cầu GET đến API mẫu jsonplaceholder.

  • Kiểm tra nếu xhr.status === 200 thì xử lý dữ liệu.

  • Dùng onerror để bắt lỗi nếu có sự cố mạng.


2. Gửi POST request với dữ liệu JSON

Mục tiêu: Gửi một đối tượng JSON đến server và xử lý phản hồi.

const xhr = new XMLHttpRequest();
xhr.open("POST", "https://jsonplaceholder.typicode.com/posts", true);
xhr.setRequestHeader("Content-Type", "application/json");

xhr.onload = function () {
  if (xhr.status === 201) {
    const response = JSON.parse(xhr.responseText);
    console.log("Phản hồi từ server:", response);
  } else {
    console.error("Lỗi khi gửi dữ liệu:", xhr.status);
  }
};

const data = {
  title: "Bài viết mới",
  body: "Nội dung bài viết",
  userId: 1
};

xhr.send(JSON.stringify(data));

Giải thích:

  • Gửi yêu cầu POST với tiêu đề Content-Type: application/json.

  • Gửi dữ liệu JSON về server.

  • Kiểm tra mã 201 Created để xác nhận thành công.


3. Hiển thị thông báo lỗi khi server trả về mã lỗi

Mục tiêu: Bắt và hiển thị lỗi rõ ràng khi server trả về mã lỗi như 404 hoặc 500.

const xhr = new XMLHttpRequest();
xhr.open("GET", "https://jsonplaceholder.typicode.com/khongton_tai", true);

xhr.onload = function () {
  if (xhr.status >= 200 && xhr.status < 300) {
    console.log("Dữ liệu:", xhr.responseText);
  } else {
    alert(`Có lỗi xảy ra: ${xhr.status} - ${xhr.statusText}`);
  }
};

xhr.onerror = function () {
  alert("Không thể kết nối tới server.");
};

xhr.send();

Giải thích:

  • Kiểm tra mã trạng thái HTTP (xhr.status) để xác định lỗi.

  • Hiển thị thông báo rõ ràng cho người dùng qua alert() hoặc cập nhật giao diện.

  • xhr.onerror sẽ kích hoạt nếu có lỗi kết nối mạng.

Các ví dụ trên minh họa cách sử dụng XMLHttpRequest trong các tình huống cơ bản:

Tình huống Phương pháp
Gửi yêu cầu GET xhr.open("GET", url) + xhr.send()
Gửi yêu cầu POST xhr.open("POST", url) + xhr.setRequestHeader()
Xử lý lỗi HTTP hoặc mạng Kiểm tra xhr.status và dùng xhr.onerror

VII. Ứng dụng thực tế của AJAX và XMLHttpRequest

AJAX kết hợp với XMLHttpRequest được sử dụng phổ biến trong nhiều tính năng hiện đại trên web. Dưới đây là một số ứng dụng tiêu biểu:

1. Tìm kiếm gợi ý theo thời gian thực (Autocomplete)

  • Khi người dùng gõ từ khóa vào ô tìm kiếm, AJAX gửi yêu cầu đến server và nhận về danh sách gợi ý phù hợp mà không cần tải lại trang.

  • Ví dụ: tìm kiếm sản phẩm, tên người dùng, địa điểm...

2. Gửi form đăng ký/đăng nhập không cần reload

  • Thay vì submit form truyền thống, AJAX giúp gửi dữ liệu đăng ký hoặc đăng nhập mà không làm tải lại trang.

  • Tạo cảm giác liền mạch, nhanh chóng và cải thiện UX.

3. Tải thêm nội dung động

  • Ví dụ: Tải thêm bình luận, bài viết, sản phẩm khi người dùng nhấn “Xem thêm” hoặc kéo xuống dưới cùng.

  • Giúp trang web hiển thị nhanh và nhẹ ban đầu.

4. Cập nhật dashboard hoặc dữ liệu theo thời gian thực

  • Trong các ứng dụng quản trị, AJAX được dùng để cập nhật biểu đồ, thông báo, số liệu mà không phải refresh toàn trang.

  • Giúp quản trị viên theo dõi dữ liệu "sống" như đơn hàng, lượt truy cập, thông báo mới.


VIII. Ưu điểm và hạn chế

Ưu điểm

  1. Giao diện mượt mà hơn
    AJAX giúp cập nhật nội dung một phần của trang mà không tải lại toàn bộ, mang lại trải nghiệm mượt mà.

  2. Trải nghiệm người dùng tốt hơn
    Người dùng không phải chờ lâu, thao tác nhanh và không bị gián đoạn khi dữ liệu được cập nhật động.

  3. Giảm tải cho server
    Chỉ truyền dữ liệu cần thiết thay vì tải lại toàn bộ trang HTML, giúp tối ưu hiệu suất mạng và server.

  4. Cập nhật dữ liệu linh hoạt
    AJAX có thể hoạt động định kỳ hoặc theo sự kiện, thích hợp cho các trang có dữ liệu thay đổi liên tục.


Hạn chế

  1. Cú pháp XMLHttpRequest dài dòng hơn Fetch API
    Dù mạnh mẽ, nhưng cú pháp XMLHttpRequest phức tạp và dễ gây lỗi, nhất là khi xử lý nhiều trạng thái.

  2. Xử lý lỗi thủ công
    Khi dùng XMLHttpRequest, cần tự xử lý đầy đủ các trường hợp lỗi như 404, 500, timeout hoặc lỗi mạng.

  3. Không phù hợp với trình duyệt quá cũ hoặc cấu hình bảo mật thấp
    Một số trình duyệt cũ hoặc trang web không hỗ trợ HTTPS sẽ không thể sử dụng AJAX an toàn và hiệu quả.


IX. Một số lưu ý khi sử dụng XMLHttpRequest

Để sử dụng XMLHttpRequest hiệu quả và an toàn, cần lưu ý:

1. Luôn kiểm tra trạng thái .readyState.status

  • .readyState === 4 đảm bảo phản hồi đã hoàn tất.

  • .status === 200 (hoặc mã thành công khác như 201) đảm bảo server phản hồi thành công.

if (xhr.readyState === 4 && xhr.status === 200) {
  // xử lý dữ liệu
}

2. Xác định rõ định dạng dữ liệu (JSON, XML…)

  • Phải biết trước server trả về định dạng nào để xử lý đúng cách.

  • Ví dụ: Nếu là JSON, cần JSON.parse(xhr.responseText).

3. Thêm xử lý trạng thái loading, lỗi và timeout

  • Tránh để người dùng phải chờ không biết chuyện gì đang diễn ra.

  • Ví dụ: Hiển thị spinner khi chờ phản hồi, thông báo lỗi khi thất bại.

4. Tránh lỗi Cross-Origin (CORS)

  • Nếu gọi đến API từ domain khác, cần đảm bảo server hỗ trợ CORS (Access-Control-Allow-Origin).

  • AJAX không thể gọi thành công nếu không có quyền từ server.

5. Chú ý bảo mật khi gửi dữ liệu

  • Không gửi thông tin nhạy cảm qua phương thức GET.

  • Luôn mã hóa hoặc bảo vệ dữ liệu nhạy cảm, xác thực người dùng, và sử dụng HTTPS để đảm bảo an toàn.

Kết luận

AJAX và đối tượng XMLHttpRequest là nền tảng quan trọng giúp xây dựng các ứng dụng web hiện đại, cho phép tương tác với máy chủ một cách mượt mà và linh hoạt mà không cần tải lại toàn bộ trang. Dù ngày nay Fetch API đã trở nên phổ biến hơn nhờ cú pháp đơn giản và hỗ trợ Promise, XMLHttpRequest vẫn là một phần kiến thức cơ bản không thể thiếu với những ai muốn hiểu rõ cách web vận hành ở mức thấp.

Việc sử dụng AJAX đúng cách không chỉ giúp cải thiện hiệu suất và trải nghiệm người dùng mà còn tạo tiền đề cho việc phát triển các ứng dụng thời gian thực, như công cụ tìm kiếm thông minh, bảng điều khiển tương tác, và hệ thống phản hồi nhanh. Tuy nhiên, bên cạnh đó, các vấn đề về bảo mật, xử lý lỗi và cấu hình hệ thống cũng cần được chú ý kỹ lưỡng để đảm bảo hệ thống vận hành ổn định và an toàn.

Nắm vững XMLHttpRequest không chỉ giúp bạn xử lý các tác vụ bất đồng bộ hiệu quả mà còn giúp bạn hiểu sâu hơn về cách dữ liệu được trao đổi giữa client và server — nền tảng cho việc phát triển các ứng dụng web hiện đại ngày nay.

Bài viết liên quan