Lỗi XmlHttpRequest: Không cho phép nguồn gốc null của Access-Control-Allow-Origin


550

Tôi đang phát triển một trang lấy hình ảnh từ Flickr và Panoramio thông qua hỗ trợ AJAX của jQuery.

Phía Flickr đang hoạt động tốt, nhưng khi tôi cố gắng $.get(url, callback)từ Panoramio, tôi thấy một lỗi trong bảng điều khiển của Chrome:

XMLHttpRequest không thể tải http://www.panoramio.com/wapi/data/get_photos?v=1&key=dummykey&tag=test&offset=0&length=20&callback= ProcessImages & minx = 30 & miny = 0 & max = . Nguồn gốc null không được cho phép bởi Access-Control-Cho phép Xuất xứ.

Nếu tôi truy vấn URL đó từ trình duyệt trực tiếp, nó hoạt động tốt. Điều gì đang xảy ra, và tôi có thể giải quyết vấn đề này không? Tôi đang soạn thảo truy vấn của mình không chính xác hay đây là điều mà Panoramio làm để cản trở những gì tôi đang cố gắng thực hiện?

Google đã không bật bất kỳ kết quả hữu ích nào trên thông báo lỗi .

BIÊN TẬP

Đây là một số mã mẫu cho thấy vấn đề:

$().ready(function () {
  var url = 'http://www.panoramio.com/wapi/data/get_photos?v=1&key=dummykey&tag=test&offset=0&length=20&callback=processImages&minx=-30&miny=0&maxx=0&maxy=150';

  $.get(url, function (jsonp) {
    var processImages = function (data) {
      alert('ok');
    };

    eval(jsonp);
  });
});

Bạn có thể chạy ví dụ trực tuyến .

CHỈNH SỬA 2

Cảm ơn Darin vì sự giúp đỡ của anh ấy với điều này. MÃ SỐ TRÊN LÀ SAI. Sử dụng cái này thay thế:

$().ready(function () {
  var url = 'http://www.panoramio.com/wapi/data/get_photos?v=1&key=dummykey&tag=test&offset=0&length=20&minx=-30&miny=0&maxx=0&maxy=150&callback=?';

  $.get(url, function (data) {
    // can use 'data' in here...
  });
});

1
Gì URL trông giống như bạn đang đưa ra yêu cầu từ ? Điều này không xảy ra được một tạo động iframemà bạn document.writevào, ví dụ?
Pekka

5
Bạn có thể gửi phản hồi HTTP từ yêu cầu đến từng dịch vụ. Tôi cá là Panoramio không phục vụ Access-Control-Allow-Origin. Xem w3.org/TR/cors để biết ví dụ.
Kevin Hakanson

2
@Kevin, bạn không cần những tiêu đề đó nếu máy chủ gửi JSONP.
Darin Dimitrov

@Pekka, hiện tại tôi đang chạy trang từ máy cục bộ của mình ( file:///C:/). Không có iframeliên quan.
Drew Noakes

1
@drew điều gì xảy ra nếu bạn chạy nó từ một URL http? Nó không nên tạo ra sự khác biệt theo cách này, nhưng chỉ để loại trừ khả năng.
Pekka

Câu trả lời:


423

Đối với hồ sơ, theo như tôi có thể nói, bạn có hai vấn đề:

  1. Bạn không chuyển một trình xác định loại "jsonp" cho bạn $.get, vì vậy nó đang sử dụng một XMLHttpRequest thông thường. Tuy nhiên, trình duyệt của bạn đã hỗ trợ CORS (Chia sẻ tài nguyên nguồn gốc chéo) để cho phép XMLHttpRequest tên miền chéo nếu máy chủ đồng ý. Đó là nơi Access-Control-Allow-Origintiêu đề đến.

  2. Tôi tin rằng bạn đã đề cập rằng bạn đang chạy nó từ một tệp: // URL. Có hai cách để các tiêu đề CORS báo hiệu rằng XHR tên miền chéo là OK. Một là gửi Access-Control-Allow-Origin: *(mà nếu bạn đã truy cập Flickr thông qua $.get, họ chắc chắn đã làm) trong khi cách khác là để trả lại nội dung của Origintiêu đề. Tuy nhiên, file://URL tạo ra một giá trị Originkhông thể được cấp phép thông qua phản hồi lại.

Cách đầu tiên đã được giải quyết theo cách vòng qua theo đề nghị của Darin $.getJSON. Nó thực hiện một phép thuật nhỏ để thay đổi loại yêu cầu từ mặc định là "json" thành "jsonp" nếu nó thấy chuỗi con callback=?trong URL.

Điều đó đã giải quyết lần thứ hai bằng cách không còn cố gắng thực hiện yêu cầu CORS từ file://URL.

Để làm rõ cho những người khác, đây là các hướng dẫn khắc phục sự cố đơn giản:

  1. Nếu bạn đang cố gắng sử dụng JSONP, hãy đảm bảo một trong những trường hợp sau:
    • Bạn đang sử dụng $.getvà thiết lập dataTypeđể jsonp.
    • Bạn đang sử dụng $.getJSONvà bao gồm callback=?trong URL.
  2. Nếu bạn đang cố gắng thực hiện một XMLHttpRequest tên miền chéo thông qua CORS ...
    1. Hãy chắc chắn rằng bạn đang thử nghiệm thông qua http://. Các tập lệnh chạy qua file://có hỗ trợ hạn chế cho CORS.
    2. Hãy chắc chắn rằng trình duyệt thực sự hỗ trợ CORS . (Opera và Internet Explorer bị trễ bữa tiệc)

45
Vậy đâu là giải pháp cho vấn đề này?
jQuerybeast

19
gọi lại =? FTW
Tim

10
Một số trình duyệt như chrome cho phép CORS nếu bắt đầu với các tập tin-file-access-từ---allow tham số
echox

1
callback=?Không làm việc cho tôi, nhưng jsonp=?đã làm. Bất kỳ lời giải thích cho điều đó?
viêm khớp

1
Tôi có phải cài đặt máy chủ web để kiểm tra http://không? Hoặc có cách nào để mở tập tin bằng giao thức đó không?
Will Sewell

76

Bạn cần có thể thêm một TIÊU ĐỀ trong tập lệnh được gọi của bạn, đây là những gì tôi phải làm trong PHP:

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

Thêm chi tiết trong dịch vụ AJAX tên miền chéo WEB (bằng tiếng Pháp).


1
@Uri: Phụ thuộc vào máy chủ HTTP của bạn. Với Apache, bạn sẽ muốn xem xét mod_headers.
ssokolow

4
@Uri <meta http-Equiv = "Kiểm soát truy cập-Cho phép-Xuất xứ" nội dung = "*">
Herberth Amaral

7
@HerberthAmaral Tôi đã thử thêm phần này vào bên trong <head> </ head>, nhưng nó không hoạt động với tôi. Tôi đang dùng thử trong iOS Safari và Chrome, nhưng trong bảng điều khiển, tôi nhận được null gốc không được phép do lỗi Access-Control-Allow-Origin.
thandasoru

3
Nó không hoạt động trong phần đầu của tệp html vì lý do bảo mật. Nó phải là một tiêu đề. stackoverflow.com/questions/7015782/ Mạnh
Justin Blank

Nó không thể có trong HTML. Nó phải được chỉ định bởi chương trình đang gửi trang HTML tới trình duyệt của bạn qua mạng (được gọi là máy chủ web).
Roman Plášil

70

Đối với một dự án HTML đơn giản:

cd project
python -m SimpleHTTPServer 8000

Sau đó duyệt tập tin của bạn.


1
trong khi tuyệt vời và hoạt động, khi bạn truy cập 0.0.0.0:8000 và thử POSTyêu cầu bạn nhận được: code 501, message Unsupported method ('POST')cho các googles.
pjammer

"Khi một máy chủ web Python (ví dụ như cherrypy) cho biết nó đang phục vụ vào ngày 0.0.0.0, điều đó có nghĩa là nó đang lắng nghe tất cả lưu lượng TCP kết thúc tại máy đó bất kể tên máy chủ hoặc IP được yêu cầu." Vì vậy, có thể thử đăng lên localhost: 8000 stackoverflow.com/a/4341808/102022
eric.christensen

20

Hoạt động với tôi trên Google Chrome v5.0.375.127 (tôi nhận được cảnh báo):

$.get('http://www.panoramio.com/wapi/data/get_photos?v=1&key=dummykey&tag=test&offset=0&length=20&callback=?&minx=-30&miny=0&maxx=0&maxy=150',
function(json) {
    alert(json.photos[1].photoUrl);
});

Ngoài ra, tôi sẽ khuyên bạn nên sử dụng $.getJSON()phương pháp thay vì trước đây không hoạt động trên IE8 (ít nhất là trên máy của tôi):

$.getJSON('http://www.panoramio.com/wapi/data/get_photos?v=1&key=dummykey&tag=test&offset=0&length=20&callback=?&minx=-30&miny=0&maxx=0&maxy=150', 
function(json) {
    alert(json.photos[1].photoUrl);
});

Bạn có thể thử nó trực tuyến từ đây .


CẬP NHẬT:

Bây giờ bạn đã hiển thị mã của mình, tôi có thể thấy vấn đề với nó. Bạn đang có cả chức năng ẩn danh và chức năng nội tuyến nhưng cả hai sẽ được gọi processImages. Đó là cách hoạt động của hỗ trợ JSONP của jQuery. Lưu ý cách tôi xác định callback=?để bạn có thể sử dụng hàm ẩn danh. Bạn có thể đọc thêm về nó trong tài liệu .

Một nhận xét khác là bạn không nên gọi eval. Tham số được truyền cho hàm ẩn danh của bạn sẽ được jQuery phân tích thành JSON.


Hmm ok để tôi thử lại. Tôi đang dùng phiên bản Chrome btw "6.0.472.51 beta" khác.
Drew Noakes

Mã của bạn làm việc cho tôi. Tôi đã cập nhật câu hỏi của tôi với một số mã rút ra vấn đề mặc dù.
Drew Noakes

Cảm ơn vì đã nhận được thông tin ... Tôi đã lấy ví dụ jsFiddle của bạn để hiển thị vấn đề ( jsfiddle.net/ZfvKm ) và bây giờ thấy thông báo lỗi XMLHttpRequest không thể tải panoramio.com/wapi/data/ . Origin fiddle.jshell.net không được Access-Control-Allow-Origin cho phép.
Drew Noakes

@Darin, cảm ơn đã cập nhật. Tôi thấy quan điểm của bạn và tôi đã chơi với một vài kết hợp này, nhưng tôi vẫn chưa tìm được cách truy cập đối tượng được trả về. Bạn có thể cập nhật ví dụ jsFiddle của bạn để hiển thị truy cập dữ liệu không? Nếu bạn đặt cuộc gọi lại thành ?thì JSON được trả về được bao quanh bằng dấu ngoặc đơn. Bạn không xác định tham số cho chức năng gọi lại và giá trị của thisdường như không có đối tượng phản hồi (ít nhất, .datagiá trị là null).
Drew Noakes

@Darin, tuyệt vời. Cảm ơn nhiều. Làm việc tốt bây giờ. Đối với bất kỳ ai khác đọc điều này, việc bao gồm callback=?yêu cầu jQuery tạo một tên hàm ngẫu nhiên trong nội bộ, dẫn đến một cuộc gọi đến hàm ẩn danh mà bạn chuyển đến .getJSON. Đánh giá cao.
Drew Noakes

8

Miễn là máy chủ được yêu cầu hỗ trợ định dạng dữ liệu JSON, hãy sử dụng giao diện JSONP (JSON Padding). Nó cho phép bạn thực hiện các yêu cầu tên miền bên ngoài mà không cần máy chủ proxy hoặc công cụ tiêu đề ưa thích.



4

Chúng tôi đã quản lý nó thông qua http.conftệp (được chỉnh sửa và sau đó khởi động lại dịch vụ HTTP):

<Directory "/home/the directory_where_your_serverside_pages_is">
    Header set Access-Control-Allow-Origin "*"
    AllowOverride all
    Order allow,deny
    Allow from all
</Directory>

Trong Header set Access-Control-Allow-Origin "*", bạn có thể đặt một URL chính xác.


1
cái này không hoạt động trên Apache của XAMPP. vấn đề vẫn còn tồn tại
Raptor

1
Điều này là không an toàn. Xem ở đây tại sao; stackoverflow.com/questions/7564832/ Mạnh
Cướp

Nó không an toàn như @RobQuist nói.
D337

4

Nếu bạn đang thực hiện kiểm tra cục bộ hoặc gọi tệp từ một cái gì đó như thế file://thì bạn cần phải tắt bảo mật trình duyệt.

Trên MAC: open -a Google\ Chrome --args --disable-web-security


3

Trong trường hợp của tôi, cùng một mã hoạt động tốt trên Firefox, nhưng không phải trên Google Chrome. Bảng điều khiển JavaScript của Google Chrome cho biết:

XMLHttpRequest cannot load http://www.xyz.com/getZipInfo.php?zip=11234. 
Origin http://xyz.com is not allowed by Access-Control-Allow-Origin.
Refused to get unsafe header "X-JSON"

Tôi đã phải bỏ phần www của URL Ajax để khớp chính xác với URL gốc và sau đó nó hoạt động tốt.


2

Không phải tất cả các máy chủ đều hỗ trợ jsonp. Nó yêu cầu máy chủ thiết lập chức năng gọi lại trong kết quả của nó. Tôi sử dụng điều này để nhận được phản hồi json từ các trang web trả về json thuần túy nhưng không hỗ trợ jsonp:

function AjaxFeed(){

    return $.ajax({
        url:            'http://somesite.com/somejsonfile.php',
        data:           {something: true},
        dataType:       'jsonp',

        /* Very important */
        contentType:    'application/json',
    });
}

function GetData() {
    AjaxFeed()

    /* Everything worked okay. Hooray */
    .done(function(data){
        return data;
    })

    /* Okay jQuery is stupid manually fix things */
    .fail(function(jqXHR) {

        /* Build HTML and update */
        var data = jQuery.parseJSON(jqXHR.responseText);

        return data;
    });
}

1

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.


1

Như lưu ý cuối cùng, tài liệu Mozilla nói rõ ràng rằng

Ví dụ trên sẽ thất bại nếu tiêu đề được ký tự đại diện là: Access-Control-Allow-Origin: *. Vì Access-Control-Allow-Origin đề cập rõ ràng http: //foo.example , nên nội dung nhận thức thông tin xác thực được trả về nội dung web gọi.

Kết quả là không chỉ đơn giản là một thực hành xấu để sử dụng '*'. Đơn giản là không hoạt động :)


1

Đối với PHP - công việc này đối với tôi trên Chrome, safari và firefox

https://w3c.github.io/webappsec-cors-for-developers/#avoid-retinating-access-control-allow-origin-null

header('Access-Control-Allow-Origin: null');

sử dụng axios gọi dịch vụ trực tiếp php với tệp: //


Điều này cũng hoạt động với tôi, Lưu ý cách null là một chuỗi và không phải là NULL thực tế. Tôi sử dụng nó vì nó cũng header('Access-Control-Allow-Origin: '.( trim($_SERVER['HTTP_REFERER'],'/') ?:'null'),true);cho phép xuất phát chéo từ một máy chủ từ xa sang một máy chủ khác và rơi vào (chuỗi) null cho tệp cục bộ.
Louis Loudog Trottier

0

Tôi cũng gặp lỗi tương tự trong Chrome (Tôi đã không kiểm tra các trình duyệt khác). Đó là do thực tế là tôi đã điều hướng trên domain.com thay vì www.domain.com. Hơi lạ một chút, nhưng tôi có thể giải quyết vấn đề bằng cách thêm các dòng sau vào .htaccess. Nó chuyển hướng domain.com đến www.domain.com và vấn đề đã được giải quyết. Tôi là một người truy cập web lười biếng vì vậy tôi gần như không bao giờ gõ www nhưng rõ ràng trong một số trường hợp nó là bắt buộc.

RewriteEngine on
RewriteCond %{HTTP_HOST} ^domain\.com$ [NC]
RewriteRule ^(.*)$ http://www.domain.com/$1 [R=301,L]

0

Hãy chắc chắn rằng bạn đang sử dụng phiên bản mới nhất của JQuery. Chúng tôi đã gặp phải lỗi này đối với JQuery 1.10.2 và lỗi đã được khắc phục sau khi sử dụng JQuery 1.11.1


0

Mọi người,

Tôi gặp phải một vấn đề tương tự. Nhưng sử dụng Fiddler, tôi đã có thể gặp vấn đề. Vấn đề là URL máy khách được định cấu hình trong triển khai CORS ở phía API Web không được có dấu gạch chéo phía trước. Sau khi gửi yêu cầu của bạn qua Google Chrome và kiểm tra tab TextView của phần Tiêu đề của Fiddler, thông báo lỗi cho biết đại loại như sau:

* "Chính sách được chỉ định nguồn gốc your_client_url: / 'không hợp lệ. Nó không thể kết thúc bằng dấu gạch chéo về phía trước."

Điều này thực sự kỳ quặc bởi vì nó hoạt động mà không có bất kỳ vấn đề nào trên Internet Explorer, nhưng khiến tôi đau đầu khi thử nghiệm bằng Google Chrome.

Tôi đã xóa dấu gạch chéo về phía trước trong mã CORS và biên dịch lại API Web và bây giờ API có thể truy cập qua Chrome và Internet Explorer mà không gặp sự cố nào. Xin vui lòng cho điều này một shot.

Cảm ơn, Andy


0

Có một vấn đề nhỏ trong giải pháp được đăng bởi CodeGroover ở trên , nếu bạn thay đổi tệp, bạn sẽ phải khởi động lại máy chủ để thực sự sử dụng tệp đã cập nhật (ít nhất là trong trường hợp của tôi).

Vì vậy, tìm kiếm một chút, tôi tìm thấy cái này để sử dụng:

sudo npm -g install simple-http-server # to install
nserver # to use

Và sau đó nó sẽ phục vụ tại http://localhost:8000.


1
Mặc dù liên kết này có thể trả lời câu hỏi, tốt hơn là bao gồm các phần thiết yếu của câu trả lời ở đây và cung cấp liên kết để tham khảo. Câu trả lời chỉ liên kết có thể trở nên không hợp lệ nếu trang được liên kết thay đổi. - Từ đánh giá
Vi100

Làm rõ các liên kết.
MiJyn
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.