2008-12-02 10 views
22

Tôi cần thực hiện yêu cầu AJAX từ trang web đến dịch vụ web REST được lưu trữ trong miền khác.Yêu cầu AJAX chéo trang

Mặc dù điều này chỉ hoạt động tốt trong Internet Explorer, các trình duyệt khác như Mozilla và Google Chrome áp đặt các giới hạn bảo mật nghiêm ngặt hơn, ngăn cấm các yêu cầu AJAX chéo trang.

Vấn đề là tôi không có quyền kiểm soát miền hoặc máy chủ web nơi trang web được lưu trữ. Điều này có nghĩa rằng dịch vụ web REST của tôi phải chạy ở một nơi khác và tôi không thể đặt bất kỳ cơ chế chuyển hướng nào.

Đây là đoạn mã JavaScript mà làm cho các cuộc gọi không đồng bộ:

var serviceUrl = "http://myservicedomain"; 
var payload = "<myRequest><content>Some content</content></myRequest>"; 
var request = new XMLHttpRequest(); 
request.open("POST", serviceUrl, true); // <-- This fails in Mozilla Firefox amongst other browsers 
request.setRequestHeader("Content-type", "text/xml"); 
request.send(payload); 

Làm thế nào tôi có thể có công việc này trong các trình duyệt khác bên cạnh Internet Explorer?

+1

@PhiLho Trong trường hợp này, mục tiêu của tôi là gọi một dịch vụ REST được lưu trữ trên một miền khác, không bao gồm nội dung động. –

Trả lời

14

có thể JSONP có thể trợ giúp.

NB bạn sẽ phải thay đổi thông điệp của bạn để sử dụng json thay vì xml

Sửa

các trang web lớn như Flickr và twitter hỗ trợ jsonp với callbacks vv

+0

điều này có thể hoạt động, nhưng JSONP là một sự thừa nhận rằng có điều gì đó sai :) – annakata

+0

mức độ phổ biến của phương pháp này là gì? Nó có vẻ là loại thử nghiệm. –

+0

@annakata rõ ràng nhưng ông đã gặp ông không có xử lý trên máy chủ web, do đó, bằng cách sử dụng một proxy là ra khỏi cửa sổ. Tôi không ở đây để bình luận về tình hình của anh ta chỉ cung cấp một giải pháp khả thi cho câu hỏi/vấn đề của anh ấy. – redsquare

3

Việc này làm việc trong IE là một vấn đề bảo mật với IE, không phải là một tính năng.

Thật không may là việc tạo mã cross-site bị cấm và công việc được chấp nhận xung quanh là ủy quyền các yêu cầu thông qua miền của riêng bạn: bạn có thực sự không có khả năng thêm hoặc sửa đổi mã phía máy chủ không? Hơn nữa, cách giải quyết thứ hai - liên quan đến việc thu thập dữ liệu thông qua thẻ tập lệnh - chỉ hỗ trợ các yêu cầu GET mà bạn có thể hack với dịch vụ SOAP, nhưng không quá nhiều với yêu cầu POST tới RESTful dịch vụ bạn mô tả.

Tôi thực sự không chắc chắn giải pháp AJAX tồn tại, bạn có thể quay lại giải pháp < mẫu >.

+0

Tôi đồng ý rằng cho phép XSS là một lỗ hổng bảo mật trong IE. Thật không may, tôi không có quyền kiểm soát máy chủ web vì đó là một blog được lưu trữ trên một nhà cung cấp bên thứ ba. Tôi cũng nghĩ về việc sử dụng các biểu mẫu HTML, nhưng điều đó sẽ gây ra một bài đăng đầy đủ trên trang thay vì một cuộc gọi không đồng bộ tốt đẹp. –

3

Cách giải quyết không rõ ràng (nhưng hoạt động) đang sử dụng iframe làm vùng chứa cho các yêu cầu đến một trang web khác. Vấn đề là, cha mẹ không thể truy cập nội dung của khung nội tuyến, chỉ có thể điều hướng thuộc tính "src" của khung nội tuyến. Nhưng nội dung iframe có thể truy cập nội dung của cha mẹ.

Vì vậy, nếu nội dung của khung nội tuyến biết, họ có thể gọi một số nội dung javascript trong trang gốc hoặc truy cập trực tiếp vào DOM của cha mẹ.

EDIT: mẫu:

function ajaxWorkaroung() { 
    var frm = gewtElementById("myIFrame") 
    frm.src = "http://some_other_domain" 
} 
function ajaxCallback(parameter){ 
    // this function will be called from myIFrame's content 
} 
+2

IFrame chậm hơn ajax, và cũng trong IE cũ hơn tôi nhớ có âm thanh 'click' phát mọi cập nhật iframe.src: ( – Thinker

+0

Trong javascript không thể truy cập dữ liệu javascript mẹ hoặc chức năng miền chéo. Câu trả lời là không đúng – naugtur

+0

@nagtur: Tôi đã sử dụng thành công kịch bản này trong một thời gian trước đây: | – TcKs

5

Các bài đánh dấu là câu trả lời là sai lầm: tài liệu iframe là không thể truy cập vào cha mẹ. Chính sách gốc tương tự cũng hoạt động theo cả hai cách.

Thực tế là không thể thực hiện bất kỳ cách nào để sử dụng dịch vụ web dựa trên phần còn lại bằng cách sử dụng xmlhttprequest. Cách duy nhất để tải dữ liệu từ một miền khác (không có bất kỳ khung công tác nào) là sử dụng JSONP. Bất kỳ giải pháp nào khác đều yêu cầu proxy serveride nằm trên tên miền của riêng bạn hoặc proxy bên ứng dụng nằm trên miền từ xa và loại giao tiếp chéo trang web (như easyXDM) để giao tiếp giữa các tài liệu.

+0

-1 vì điều này không chính xác. Có thể truy cập trang cha từ một IFRAME bằng JavaScript bằng cách sử dụng đối tượng DOM 'cha'. Ví dụ này sẽ sửa đổi một phần tử trong trang từ bên trong một IFRAME: parent.document.getElementById ("someDiv"). innerHTML = "some content"; –

+2

Câu hỏi đặt ra là về tài liệu từ miền khác nhau - và chính sách gốc giống nhau sẽ có I effect: Một IFrame từ domainA KHÔNG thể truy cập contentDocument của parent của nó nếu cha mẹ là từ domainB. Là tác giả của easyXSS thư viện cross-site, tôi có một số kiến ​​thức về điều này. –

+0

Tôi đã hiểu sai câu trả lời của bạn sau đó. Bạn nói đúng, khung nội tuyến không thể truy cập vào nội dung và trang phó của trang gốc khi cả hai được lưu trữ trong các miền khác nhau. Tuy nhiên trong trường hợp của tôi bằng cách sử dụng iframe hoạt động tốt, bởi vì nó không cần truy cập trang cha bằng bất kỳ cách nào, nhưng nó chỉ đơn giản là gửi một yêu cầu AJAX đến một dịch vụ, được lưu trữ trên cùng một miền của nó. –

2

Làm cho miền dịch vụ của bạn chấp nhận chia sẻ nguồn gốc chéo (CORS).

Kịch bản điển hình: Hầu hết các trình duyệt tương thích CORS trước tiên sẽ gửi tiêu đề OPTIONS, trong đó máy chủ sẽ trả về thông tin về các tiêu đề được chấp nhận. Nếu tiêu đề đáp ứng các yêu cầu của dịch vụ cho yêu cầu được cung cấp (Các phương thức được phép là GET và POST, Được phép xuất xứ *, vv), thì trình duyệt sẽ gửi lại yêu cầu với phương thức thích hợp (GET, POST, v.v.).

Mọi thứ mà điểm này chuyển tiếp giống như khi bạn đang sử dụng IE, hoặc đơn giản hơn, nếu bạn đã đăng lên cùng một miền.

Caviots: Một số phát triển dịch vụ của SDK (WCF nói riêng) sẽ xử lý yêu cầu, trong trường hợp này bạn cần phải xử lý trước phương pháp OPTIONS để trả lời yêu cầu và tránh phương thức được gọi hai lần trên máy chủ.

Tóm lại, sự cố nằm ở phía máy chủ.

Chỉnh sửa Có một vấn đề với IE 9 trở xuống với CORS, ở chỗ nó không được triển khai đầy đủ. May mắn thay, bạn có thể giải quyết vấn đề này bằng cách thực hiện cuộc gọi từ mã phía máy chủ đến dịch vụ và đưa nó trở lại thông qua máy chủ của bạn (ví dụ: mypage.aspx? Service = blah & method = blahblah & p0 = firstParam = something). Từ đây, mã phía máy chủ của bạn nên triển khai mô hình luồng yêu cầu/phản hồi.

0

Điều này cũng có thể được thực hiện bằng cách sử dụng thiết lập máy chủ web localy gọi curl với các đối số chính xác và trả về đầu ra curl.

app.rb

require 'sinatra' 
require 'curb' 

set :views,lambda {"views/"+self.name.to_s.downcase.sub("controller","")} 
set :haml, :layout => :'../layout', :format => :html5, :escape_html=>true 
disable :raise_errors 

get '/data/:brand' do 
    data_link = "https://externalsite.com/#{params[:brand]}" 
    c = Curl::Easy.perform(data_link) 
    c.body_str 
end 

Gửi một yêu cầu ajax với localhost: 4567/data/cái gì đó sẽ trả về kết quả từ externalsite.com/something.

0

Tùy chọn khác sẽ là thiết lập bản ghi CNAME trên miền của riêng bạn thành "Mặt nạ" tên miền máy chủ từ xa.