Cross-Domain Ajax Requests
https://viblo.asia/p/cross-domain-ajax-requests-l5y8Rr52vob3
Cross-Domain Ajax Requests
Mở đầu
Same-origin policy là một khái niệm quan trọng trong mô hình bảo mật thông tin web. Đây là một chính sách dành cho các browser, browser chỉ được cho phép các đoạn script ở trang web thứ nhất truy cập vào dữ liệu ở trang web thứ hai khi mà hai trang đó có cùng nguồn (same-origin). Chính sách này ra đời nhằm mục đích ngăn cản các script độc hại ở một trang lấy các thông tin nhạy cảm ở một trang khác. Tuy nhiên nó cũng gây ra một số khó khăn trong quá trình phát triển web như không cho phép gửi AJAX request từ một trang đến trang khác không cùng domain để lấy dữ liệu. Việc gửi cross-domain AJAX request đôi khi là cần thiết, chẳng hạn khi bạn có một API server và muốn cung cấp cho các dịch vụ khác truy cập qua JavaScript. Ở bài viết mình xin giới thiệu một số cách để thực hiện AJAX request giữa các domain khác nhau, hi vọng sẽ giúp ích cho các bạn.
1. JSONP (JSON with padding)
Tuy chúng ta không thể gửi được AJAX request từ một domain này đến một domain khác, nhưng chúng ta có thể dùng thẻ <script>
với thuộc tính src
để load JavaScript từ bất kì domain nào. JSONP hoạt động trên nguyên tắc này, nó tự động tạo ra thẻ <script>
để load code JavaScript từ phía server và thực thi đoạn code đó.
Dưới đây là một ví dụ đơn giản của việc dùng JSONP để thực thi cross-domain AJAX
Lúc này cặp thẻ <script>
với nội dung như dưới sẽ được tạo ra
Ở phía server sẽ cần phải thay đổi dạng của response, nếu như bình thường server trả về response là HTML với nội dung
thì để dùng JSONP server phải trả về JavaScript với nội dung
Ở ví dụ trên nếu như không chỉ định tên của callback function thì jQuery sẽ tự sinh ngẫu nhiên tên function (ví dụ: jQuery1111015991538995876908_1437907666364
), khi đó code JavaScript có thể được viết lại ngắn hơn 1 chút
Ưu điểm và nhược điểm
Ưu điểm:
Dễ dàng implement ở phía client
Sử dụng được với tất cả các browser
Nhược điểm
Cần sự hỗ trợ phía server
Chỉ gửi được GET request
Không thể gửi header kèm theo
2. CORS
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 đó. CORS tận dụng HTTP headers để hỗ trợ browser quyết định xem trường hợp nào có thể cho phép thực hiện cross-domain request và trường hợp nào không. Về cơ bản, khi chúng ta thực hiện 1 cross-origin request, browser sẽ gửi kèm header Origin
có giá trị là domain hiện tại. Ví dụ:
Ở phía server khi tiếp nhận request sẽ kiểm tra xem domain này có được phép truy cập không, nếu được thì server trả về response với header Access-Control-Allow-Origin
. Giá trị của header này cũng chính là domain nơi mà script gửi cross-origin request được thực thi, trong trường hợp này là
Khi nhận được response từ server, browser kiểm tra xem header Access-Control-Allow-Origin
có tồn tại hay không và có trùng với domain hiện tại hay không, nếu ok thì sẽ cho phép xử lí response.
Để có thể dùng được CORS thì chúng ta cần sự hỗ trợ từ cả 2 phía client và server.
Về phía client, CORS hiện nay đã được hỗ trợ bởi hầu hết các trình duyệt, chi tiết các bạn có thể xem ở hình dưới (nguồn: http://caniuse.com/#search=cors)
Khi thực hiện CORS request, chúng ta dùng
XMLHttpRequest
trên Firefox 3.5+, Chrome, Safari 4+, IE 10+ vàXDomainRequest
trên IE 8, 9. Do jQuery đã hỗ trợXMLHttpRequest
một cách tự động nên chúng ta có thể tạo AJAX request như bình thường mà không phải thay đổi code JavaScript.
Đối với XDomainRequest
thì xử lí hơi phức tạp hơn một chút, do không được jQuery hỗ trợ nên chúng ta cần dùng plugin ngoài nếu như không muốn phải tạo XDomainRequest
một cách thủ công. Có một thư viện hỗ trợ rất tốt việc này đó là jquery.xdomainrequest.js
. Khi đã dùng thư viện này thì chúng ta cũng có thể tạo AJAX request một cách bình thường, tuy nhiên XDomainRequest
có những hạn chế như sau:
Protocol chỉ có thể là HTTP hoặc HTTPS
Scheme của URL nơi gửi request và nơi nhận request phải giống nhau (Vd: script đặt ở http://my-domain.com sẽ không thể gửi request đến https://other-domain.com do hai URL khác scheme)
HTTP method chỉ có thể là GET hoặc POST. Khi gửi POST request,
Content-Type
của header chỉ có thể làtext/plain
Không thể gửi kèm custom header
Về phía server, cần phải tiến hành kiểm tra xem domain của request có hợp lệ hay không và gửi về header
Access-Control-Allow-Origin
kèm theo response. Nếu như server được phát triển bằng Rails thì chúng ta có thể dùng gemrack-cors
. Sau khi cài gem, chúng ta cần thêm đoạn code sau đây vào fileconfig/application.rb
Ưu điểm và nhược điểm
Ưu điểm:
Dễ dàng implement ở phía client
Sử dụng được với hầu hết các browser
Gửi được request với tất cả các loại HTTP method (trừ IE 8, 9; tùy setting phía server)
Gửi được custom header kèm theo (trừ IE 8, 9; tùy setting phía server)
Nhược điểm
Cần sự hỗ trợ phía server
Trên IE 8, 9 có nhiều hạn chế
IE 7 trở xuống không hỗ trợ (who cares? (yaoming))
3. Proxy
Về mặt ý tưởng đây có lẽ là cách đơn giản nhất. Nếu như không được phép thực hiện cross-domain AJAX request thì chúng ta chuyển sang same-domain request (haha). Nguyên lý là chúng ta sẽ chuẩn bị một proxy server đặt tại domain giống với domain gửi AJAX request, proxy này có nhiệm vụ nhận request và chuyển hướng request sang domain bên ngoài. Do thực hiện request đến domain bên ngoài ở phía server nên chúng ta sẽ không gặp phải bất kì hạn chế nào liên quan đến same-origin policy.
Việc chuẩn bị một proxy nói chung là phức tạp nhưng để demo cách thức hoạt động của phương pháp này mình xin được đưa ra 1 ví dụ với Rails. Đây là 1 cách implement đơn giản, proxy thực chất là một controller đặt tại http://my-domain.com/ajax
, có nhiệm vụ nhận và chuyển hướng request đến http://other-domain.com
.
Khi gửi AJAX request thì chúng ta chỉ cần thay đổi url là được, lúc này request đã trở thành same-domain request (yeah)
Ưu điểm và nhược điểm
Ưu điểm:
Sử dụng được với tất cả các browser
Gửi được request với tất cả các loại HTTP method
Gửi được custom header kèm theo
Nhược điểm
Implement ở phía server phức tạp
Tốc độ chậm do phải request 2 lần
Tổng kết
tl;dr
tl;dr
Bài viết cũng đã khá dài nên có lẽ xin được kết thúc tại đây. Thay cho lời kết, mình xin tổng kết lại các đặc điểm của từng phương pháp trong bảng dưới để các bạn tiện tham khảo.
JSONP
CORS (XMLHttpRequest)
CORS (XDomainRequest)
Proxy
Implement phía client
Đơn giản
Đơn giản
Đơn giản
Không cần
Implement phía server
Đơn giản
Đơn giản
Đơn giản
Phức tạp
Các trình duyệt hỗ trợ
Tất cả
Hầu hết
IE 8, 9
Tất cả
HTTP method
GET
Tất cả
GET, POST
Tất cả
Gửi kèm header
Không thể
Có thể
Có thể (*)
Có thể
(*) Không thể gửi custom header
Cảm ơn các bạn đã theo dõi bài viết. (thanks)
Tài liệu tham khảo
Last updated