Tên miền chéo AJAX của jQuery


477

Đây là hai trang, test.php và testserver.php.

test.php

<script src="scripts/jq.js" type="text/javascript"></script>
<script>
    $(function() {
        $.ajax({url:"testserver.php",
            success:function() {
                alert("Success");
            },
            error:function() {
                alert("Error");
            },
            dataType:"json",
            type:"get"
        }
    )})
</script>

testserver.php

<?php
$arr = array("element1",
             "element2",
             array("element31","element32"));
$arr['name'] = "response";
echo json_encode($arr);
?>

Bây giờ vấn đề của tôi: khi cả hai tệp này nằm trên cùng một máy chủ (hoặc localhost hoặc máy chủ web), nó hoạt động và alert("Success")được gọi; Nếu nó nằm trên các máy chủ khác nhau, nghĩa là testserver.php trên máy chủ web và test.php trên localhost, nó không hoạt động và alert("Error")đang thực thi. Ngay cả khi URL bên trong ajax được thay đổi thành http://domain.com/path/to/file/testserver.php


38
Dành cho người dừng chân. Đọc phần này để có ý tưởng về cách các cuộc gọi javascript tên miền hoạt động stackoverflow.com/a/11736771/228656
Abdul Munim

1
Tôi đã viết câu trả lời cho câu hỏi này tại đây: Đang tải trang html tên miền chéo bằng jQuery AJAX - trang cuối cùng, hỗ trợ https
jherax

Câu trả lời:


412

Sử dụng JSONP .

jQuery:

$.ajax({
     url:"testserver.php",
     dataType: 'jsonp', // Notice! JSONP <-- P (lowercase)
     success:function(json){
         // do stuff with json (in this case an array)
         alert("Success");
     },
     error:function(){
         alert("Error");
     }      
});

PHP:

<?php
$arr = array("element1","element2",array("element31","element32"));
$arr['name'] = "response";
echo $_GET['callback']."(".json_encode($arr).");";
?>

Tiếng vang có thể sai, đã được một thời gian kể từ khi tôi sử dụng php. Trong mọi trường hợp bạn cần xuất callbackName('jsonString')thông báo báo giá. jQuery sẽ chuyển tên gọi lại của chính nó, vì vậy bạn cần lấy tên đó từ các thông số GET.

Và như Stefan Kendall đã đăng, $ .getJSON () là một phương thức tốc ký, nhưng sau đó bạn cần nối thêm 'callback=?'url dưới dạng tham số GET (có, giá trị là ?, jQuery thay thế phương thức này bằng phương thức gọi lại được tạo riêng của nó).


2
Tại sao bạn cần phải quay lại callbackName('/* json */')thay vì callbackName(/* json */)?
Eric

3
@eric cuộc gọi lại mong đợi một chuỗi JSON. Về mặt lý thuyết, một đối tượng có thể hoạt động tốt, nhưng không chắc jQuery phản hồi như thế nào, nó có thể gây ra lỗi hoặc thất bại trong âm thầm.
BGerrissen

Tôi nhận được lỗi sau. Cú phápError: mất tích; trước câu lệnh {"resultCode": 2}. Trong đó {"Mã kết quả": 2} là phản hồi. Làm ơn cho lời khuyên.
dùng2003356

@ user2003356 có vẻ như bạn đang trả lại JSON đơn giản thay vì JSONP. Bạn cần trả về một cái gì đó như: callbackFunction ({"resultCode": 2}). jQuery thêm tham số GET 'gọi lại' vào yêu cầu, đó là tên của hàm gọi lại mà jquery sử dụng và nên được thêm vào phản hồi.
BGerrissen

2
Đó là năm 2016. CORS hiện là một tiêu chuẩn được hỗ trợ rộng rãi, trái ngược với JSONP chỉ có thể được mô tả là hack. Câu trả lời của @ joshuarh dưới đây nên được ưu tiên ngay bây giờ.
Vicky Chijwani

202

JSONP là một lựa chọn tốt, nhưng có một cách dễ dàng hơn. Bạn chỉ có thể đặt Access-Control-Allow-Origintiêu đề trên máy chủ của bạn. Đặt nó thành *sẽ chấp nhận các yêu cầu AJAX tên miền chéo từ bất kỳ miền nào. ( https://developer.mozilla.org/en/http_access_control )

Phương pháp để làm điều này sẽ thay đổi từ ngôn ngữ sang ngôn ngữ, tất nhiên. Đây là trong Rails:

class HelloController < ApplicationController
  def say_hello
    headers['Access-Control-Allow-Origin'] = "*"
    render text: "hello!"
  end
end

Trong ví dụ này, say_hellohành động sẽ chấp nhận các yêu cầu AJAX từ bất kỳ tên miền nào và trả về phản hồi "xin chào!".

Đây là một ví dụ về các tiêu đề mà nó có thể trả về:

HTTP/1.1 200 OK 
Access-Control-Allow-Origin: *
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: text/html; charset=utf-8
X-Ua-Compatible: IE=Edge
Etag: "c4ca4238a0b923820dcc509a6f75849b"
X-Runtime: 0.913606
Content-Length: 6
Server: WEBrick/1.3.1 (Ruby/1.9.2/2011-07-09)
Date: Thu, 01 Mar 2012 20:44:28 GMT
Connection: Keep-Alive

Dễ dàng như nó là, nó có một số hạn chế trình duyệt. Xem http://caniuse.com/#feat=cors .


12
Jsonp không hỗ trợ bài, đặt và xóa. Giải pháp của bạn hoạt động tuyệt vời.
TonyTakeshi

35
trong tiêu đề PHP ("Kiểm soát truy cập-Cho phép-Xuất xứ: *");
SparK

9
@War Warrior Nếu bạn đang sử dụng .post()phương thức của jQuery, bạn phải kích hoạt hỗ trợ tên miền chéo trong jQuery. Nó được thực hiện với điều này : $.support.cors = true.
Friederike

21
Ý nghĩa bảo mật của việc cấu hình máy chủ theo cách này là gì?
Jon Schneider

19
Sẽ tốt hơn nếu chỉ cho phép những tên miền mà bạn muốn chia sẻ dữ liệu thay vì sử dụng wilcard "*".
Sebastián Grignoli

32

Bạn có thể kiểm soát điều này thông qua tiêu đề HTTP bằng cách thêm Access-Control-Allow-Origin . Đặt nó thành * sẽ chấp nhận các yêu cầu AJAX tên miền chéo từ bất kỳ miền nào.

Sử dụng PHP thật đơn giản, chỉ cần thêm dòng sau vào tập lệnh mà bạn muốn có quyền truy cập bên ngoài từ miền của mình:

header("Access-Control-Allow-Origin: *");

Đừng quên bật mô-đun mod_headers trong httpd.conf.


bạn đã cứu ngày của tôi
NomanJaving

20

Bạn cần có một cái nhìn về Chính sách xuất xứ tương tự :

Trong điện toán, chính sách nguồn gốc tương tự là một khái niệm bảo mật quan trọng đối với một số ngôn ngữ lập trình phía trình duyệt, chẳng hạn như JavaScript. Chính sách này cho phép các tập lệnh chạy trên các trang có nguồn gốc từ cùng một trang để truy cập các phương thức và thuộc tính của nhau mà không có hạn chế cụ thể, nhưng ngăn truy cập vào hầu hết các phương thức và thuộc tính trên các trang trên các trang web khác nhau.

Để bạn có thể lấy dữ liệu, nó phải là:

Cùng giao thức và máy chủ

Bạn cần triển khai JSONP để khắc phục nó.


17

Tôi đã phải tải trang web từ đĩa cục bộ "tệp: /// C: /test/htmlpage.html", gọi url "http: //localhost/getxml.php" và thực hiện điều này trong trình duyệt IE8 + và Firefox12 +, sử dụng jQuery v1 .7.2 lib để giảm thiểu mã soạn sẵn. Sau khi đọc hàng chục bài báo cuối cùng đã tìm ra nó. Dưới đây là tóm tắt của tôi.

  • tập lệnh máy chủ (.php, .jsp, ...) phải trả về tiêu đề phản hồi http Truy cập-Kiểm soát-Cho phép-Xuất xứ: *
  • trước khi sử dụng jQuery ajax, đặt cờ này trong javascript: jQuery.support.cors = true;
  • bạn có thể đặt cờ một lần hoặc mọi lúc trước khi sử dụng hàm jQuery ajax
  • bây giờ tôi có thể đọc tài liệu .xml trong IE và Firefox. Các trình duyệt khác tôi đã không kiểm tra.
  • tài liệu phản hồi có thể là đơn giản / văn bản, xml, json hoặc bất cứ điều gì khác

Dưới đây là một ví dụ cuộc gọi ajax jQuery với một số sysout gỡ lỗi.

jQuery.support.cors = true;
$.ajax({
    url: "http://localhost/getxml.php",
    data: { "id":"doc1", "rows":"100" },
    type: "GET",
    timeout: 30000,
    dataType: "text", // "xml", "json"
    success: function(data) {
        // show text reply as-is (debug)
        alert(data);

        // show xml field values (debug)
        //alert( $(data).find("title").text() );

        // loop JSON array (debug)
        //var str="";
        //$.each(data.items, function(i,item) {
        //  str += item.title + "\n";
        //});
        //alert(str);
    },
    error: function(jqXHR, textStatus, ex) {
        alert(textStatus + "," + ex + "," + jqXHR.responseText);
    }
});

1
Tôi đã viết câu trả lời cho câu hỏi này tại đây: Đang tải trang html tên miền chéo bằng jQuery AJAX - trang cuối cùng, hỗ trợ https
jherax

Đối với điểm dễ nhất: trong PHP thêm dòng này vào tập lệnh:header("Access-Control-Allow-Origin: *");
T30

1
@whome cảm ơn bạn RẤT nhiều cho câu trả lời của bạn. Bạn đã giúp tôi rất nhiều. Chúc mừng.
Luis Milanese

10

Đúng là chính sách cùng nguồn gốc ngăn JavaScript thực hiện các yêu cầu trên các miền, nhưng đặc tả CORS chỉ cho phép loại truy cập API mà bạn đang tìm kiếm và được hỗ trợ bởi hàng loạt các trình duyệt chính hiện tại.

Xem cách bật chia sẻ tài nguyên nguồn gốc cho máy khách và máy chủ:

http://enable-cors.org/

"Chia sẻ tài nguyên nguồn gốc chéo (CORS) là một đặc điểm kỹ thuật cho phép truy cập thực sự mở qua các ranh giới tên miền. Nếu bạn phục vụ nội dung công khai, vui lòng xem xét sử dụng CORS để mở ra để truy cập JavaScript / trình duyệt phổ quát."



9

Tôi sử dụng máy chủ Apache, vì vậy tôi đã sử dụng mô-đun mod_proxy. Kích hoạt các mô-đun:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

Sau đó thêm:

ProxyPass /your-proxy-url/ http://service-url:serviceport/

Cuối cùng, chuyển proxy-url vào tập lệnh của bạn.


8

Bảo mật trình duyệt ngăn thực hiện cuộc gọi ajax từ một trang được lưu trữ trên một tên miền sang một trang được lưu trữ trên một tên miền khác; đây được gọi là " chính sách cùng nguồn gốc ".



4

Từ các tài liệu Jquery ( liên kết ):

  • Do các hạn chế bảo mật của trình duyệt, hầu hết các yêu cầu "Ajax" phải tuân theo cùng chính sách xuất xứ; yêu cầu không thể truy xuất thành công dữ liệu từ một tên miền, tên miền phụ hoặc giao thức khác.

  • Các yêu cầu Script và JSONP không bị hạn chế chính sách gốc.

Vì vậy, tôi sẽ cho rằng bạn cần sử dụng jsonp cho yêu cầu. Nhưng tôi đã không thử điều này bản thân mình.


2

Tôi biết 3 cách để giải quyết vấn đề của bạn:

  1. Đầu tiên nếu bạn có quyền truy cập vào cả hai miền, bạn có thể cho phép truy cập cho tất cả các tên miền khác bằng cách sử dụng:

    header("Access-Control-Allow-Origin: *");

    hoặc chỉ một tên miền bằng cách thêm mã dưới đây vào tệp .htaccess:

    <FilesMatch "\.(ttf|otf|eot|woff)$"> <IfModule mod_headers.c> SetEnvIf Origin "http(s)?://(www\.)?(google.com|staging.google.com|development.google.com|otherdomain.net|dev02.otherdomain.net)$" AccessControlAllowOrigin=$0 Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin </IfModule> </FilesMatch>

  2. bạn có thể có yêu cầu ajax đối với tệp php trong máy chủ của mình và xử lý yêu cầu đến một tên miền khác bằng tệp php này.

  3. bạn có thể sử dụng jsonp, vì nó không cần sự cho phép. Đối với điều này, bạn có thể đọc câu trả lời @BGerrissen của bạn chúng tôi.

0

Đối với Microsoft Azure, nó hơi khác một chút.

Azure có cài đặt CORS đặc biệt cần được đặt. Về cơ bản, đó là điều tương tự đằng sau hậu trường, nhưng chỉ đơn giản là đặt tiêu đề joshuarh đề cập sẽ không hoạt động. Tài liệu Azure để kích hoạt tên miền chéo có thể được tìm thấy ở đây:

https://docs.microsoft.com/en-us/azure/app-service-api/app-service-api-cors-consume-javascript

Tôi loay hoay với điều này trong vài giờ trước khi nhận ra nền tảng lưu trữ của mình có cài đặt đặc biệt này.


0

nó hoạt động, tất cả những gì bạn cần:

PHP:

header('Access-Control-Allow-Origin: http://www.example.com');
header("Access-Control-Allow-Credentials: true");
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');

JS (jQuery ajax):

var getWBody = $.ajax({ cache: false,
        url: URL,
        dataType : 'json',
        type: 'GET',
        xhrFields: { withCredentials: true }
});
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.