Lập trình

Ajax Cross-domain toàn tập

Ajax Cross Domain là phương pháp truy vấn Ajax lấy dữ liệu từ nhiều domain khác nhau, đây là kỹ thuật cơ bản trong lập trình

Có lẽ nếu bạn là một lập trình viên, thì kiểu gì hay thế nào cũng đụng mặt với Ajax. Một trong những thuật ngữ khá cơ bản trong lập trình. Trừ khi bạn lập trình nhúng kiểu Assembly cả đời, chứ nếu không là phải đụng chạm tới Ajax và Ajax Cross-domain. Còn với những bạn lập trình front-end hay lập trình backend cho website thì chạm mặt nó cả ngày!

Okay, vậy Ajax là gì và Ajax Cross-domain là gì?

Ajax là gì?

AJAX là chữ viết tắt của cụm từ Asynchronous Javascript and XML. AJAX là phương thức trao đổi dữ liệu với máy chủ và cập nhật một hay nhiều phần của trang web. Lưu ý: Ajax là một thuật ngữ, không phải là một công nghệ. Thực tế thì nó là tập hợp của nhiều công nghệ với nhau.

Ajax được viết bằng Javascript chạy trên client, tức là mỗi browser sẽ chạy độc lập hoàn toàn không ảnh hưởng lẫn nhau. Về mặt kỹ thuật, nó đề cập đến việc sử dụng các đối tượng XmlHttpRequest để tương tác với một máy chủ web thông qua Javascript.

Trên website, Ajax có thể cập nhật các phần của website mà không phải load cả trang. Giúp tiết kiệm băng thông và nâng cao trải nghiệm của người dùng.

Ajax Cross-domain là gì?

Trong trường hợp bạn sử dụng một website X, Ajax lấy dữ liệu từ trang Y thì rất dễ thấy cái lỗi Ajax Cross-Domain như thế này:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://..../x28j5hv. (Reason: CORS header 'Access-Control-Allow-Origin' missing).

Aha, tại sao lại không lấy được dữ liệu từ trang khác về trình duyệt? Bởi đây là một chức năng bảo mật của trình duyệt. Hãy thử tưởng tượng bạn gửi một Ajax tới Facebook, mà Facebook trả về kết quả. Vậy thì ai vào trang của bạn, họ dễ dàng bị lấy cắp toàn bộ thông tin đăng nhập thông qua Cookie đúng không?

Những bạn khoái dùng jQuery cũng có Ajax Cross-domain nhưng nó không ăn thua, chỉ để chém gió:

$.ajax({
url: "https://www.dailymotion.com/embed/video/x28j5hv",
type:'GET',
contentType: "html",
crossDomain:true,
success: function(data){
   var src = $(data).html();
   alert(src);
}

Vậy trong trường hợp bạn có 3 website cần sử dụng một API để call thì làm thế nào? À ờ có nhiều cách nha các bạn. Xin giới thiệu tới các bạn các cách gọi Ajax Cross-domain sau đây:

JSONP

Chưa bao giờ mình dùng JSONP để call, mặc dù phương án này khá dễ dàng. Điểm dở của phương pháp này là chỉ dùng GET được và không thể truyền thêm header vào.

Ví dụ:

$.ajax({
  url: 'http://other-domain.com/data',
  dataType: 'jsonp',
  jsonpCallback: 'handleResponse' // chỉ định tên của callback function
});

function handleResponse(response) {
  $('#results').html(response);
}

Khi đó, về phía client bạn cần gọi qua một chuỗi script thế này:

<script src="http://other-domain.com/data?callback=handleResponse&_=1437907666366"></script>

Với cách gọi JSONP, bạn cần truyền một đối số và phải có callback. Cách này thì chỉ để truyền các biến đơn giản, hoặc để check ai đó online, hoặc làm việc gì đó cực kỳ đơn giản. Nói chung là mình ít dùng phương pháp này.

CORS

Cách ngon nhất, làm gì cũng được và trình duyệt nào cũng hỗ trợ. Cors cho phép mọi nơi và mọi trang gọi nó cho nên nó cần nhiều đối số để soi bảo mật, khai báo USER … các kiểu.

Cross-origin resource sharing (CORS) là một cơ chế đặc biệt cho phép resource đặt tại một domain này có thể được request từ một domain khác với domain đó. Ví dụ mình có 2 website cùng gọi một API, mình mở tóe loe API, trang nào ở đâu request cũng được, nhưng phải khai báo Username và mật khẩu ở header…

Về phía Client: Được hỗ trợ bởi mọi trình duyệt.

Về phía server: Cần phải được khai báo trên header để trình duyệt không block.

Với PHP:

header('Access-Control-Allow-Origin: *'); 
header("Access-Control-Allow-Credentials: true");
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');
header('Access-Control-Max-Age: 1000'); // cache
header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token , Authorization');

Nghe có vẻ dễ nhỉ! Còn ở Nodejs Server:

var express = require('express')
var cors = require('cors')
var app = express()

app.use(cors())

Dùng middleware như cors() cho nó nhanh 😀 NÓ sẽ cho phép mọi domain query tới.

Lưu ý là cho phép query từ một vài domain chỉ là cách cho zui chứ không phải là cách bảo mật nhá. Nếu dùng Proxy thì có thể query tất!

PROXY

Đây là cách chậm nhất, nhiều điểm yếu nhất. Tuy nhiên nó lại có một điểm cực mạnh đó là dù bạn có CORS hay không thì nó cũng phập hết. Để cho dễ tưởng tượng, các bạn cứ nghĩ PROXY là một trình duyệt của bạn. Nó xem qua địa chỉ AJAX sau đó chiếu lại cho bạn xem đó.

Về mặt kỹ thuật, nó cho phép chuyển hướng mọi request từ trình duyệt tới domain đích. Nói cho đơn giản là thế này:

Ajax Cross-domain Proxy
Ajax Cross-domain Proxy

Như các bạn thấy, chúng ta có một cái Server để mỗi khi nhận lệnh từ Ajax thì lấy dữ liệu bằng phương thức tương ứng từ domain khác, rồi đổ về Ajax.

Nói chung, đây là cách ít dùng, tốn tài nguyên. Trong một vài trường hợp nó như kiểu “lấy trộm” tài nguyên khi không được phép ấy!

Lưu ý với Ajax Cross-domain

Khi các bạn mở một API, bản thân các bạn cần phải xác định rằng dù bạn cấm hay hạn chế cái gì qua Cross-domain thì đó đều là tối kiến. Nó không phải là cách bảo mật. Chỉ là làm khó Client một tí mà thôi.

Vì thế, API của bạn cần xác định thêm nhiều đối số để so sánh. Ví dụ thêm mã Hash theo quy tắc của bạn. Hoặc thêm Tài khoản và mật khẩu. Hoặc bạn yêu cầu thêm header gửi kèm. Điều này hạn chế nguy cơ rủi ro về bảo mật. Chứ không phải là không cho phép CORS là có thể đảm bảo API không bị cào đâu nhé.

Chúc các bạn vui vẻ và thành công! Đừng quên xem thêm bài viết học Typescript cực đỉnh mà mình vừa soạn xong!

Thông tin liên quan

Bạn đang xem bài viết Ajax Cross-domain tại blog cá nhân của Jam. Còn rất nhiều các bài viết khác tại chuyên mục Lập trình đang được yêu thích.