jQuery AJAX ข้ามโดเมน


477

นี่คือสองหน้า test.php และ 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);
?>

ตอนนี้ปัญหาของฉัน: เมื่อไฟล์เหล่านี้ทั้งสองอยู่บนเซิร์ฟเวอร์เดียวกัน (ทั้ง localhost หรือเว็บเซิร์ฟเวอร์) มันทำงานและalert("Success")ถูกเรียก; ถ้ามันอยู่บนเซิร์ฟเวอร์ที่แตกต่างกันหมายถึง testserver.php บนเว็บเซิร์ฟเวอร์และ test.php บน localhost มันไม่ทำงานและalert("Error")กำลังดำเนินการอยู่ แม้ว่า URL ภายใน ajax จะเปลี่ยนเป็นhttp://domain.com/path/to/file/testserver.php


38
สำหรับคนหยุดโดย อ่านนี้มีความคิดวิธีจาวาสคริปต์ข้ามโดเมนเรียกทำงานstackoverflow.com/a/11736771/228656
อับดุล Munim

1
ฉันเขียนคำตอบสำหรับคำถามนี้ที่นี่: การโหลดหน้าข้ามโดเมน HTML ด้วย jQuery AJAX - หน้าสุดท้ายรองรับ https
jherax

คำตอบ:


412

ใช้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).");";
?>

เสียงก้องอาจจะผิดมานานแล้วตั้งแต่ฉันใช้ php ไม่ว่าในกรณีใด ๆcallbackName('jsonString')สังเกตคำพูด jQuery จะส่งผ่านชื่อการโทรกลับของคุณเองดังนั้นคุณต้องรับมันจาก GET params

และตามที่ Stefan Kendall โพสต์$. getJSON ()เป็นวิธีการจดชวเลข แต่จากนั้นคุณต้องผนวก'callback=?'URL เข้าไปด้วยพารามิเตอร์ GET (ใช่ค่าคือ? jQuery แทนที่วิธีนี้ด้วยวิธีการโทรกลับที่สร้างขึ้นเอง)


2
ทำไมคุณต้องกลับcallbackName('/* json */')แทนcallbackName(/* json */)?
Eric

3
@eric การเรียกกลับต้องการสตริง JSON ในทางทฤษฎีวัตถุอาจทำงานได้เช่นกัน แต่ไม่แน่ใจว่า jQuery ตอบสนองต่อสิ่งนี้อย่างไรก็อาจทำให้เกิดข้อผิดพลาดหรือล้มเหลวอย่างเงียบ ๆ
BGerrissen

ฉันได้รับข้อผิดพลาดดังต่อไปนี้ SyntaxError: ขาดหายไป; ก่อนข้อความสั่ง {"ResultCode": 2} โดยที่ {"ResultCode": 2} ตอบสนอง กรุณาแนะนำ.
user2003356

@ user2003356 ดูเหมือนว่าคุณจะส่งคืน JSON ธรรมดาแทนที่จะเป็น JSONP คุณต้องส่งคืนสิ่งที่ชอบ: callbackFunction ({"ResultCode": 2}) jQuery เพิ่มพารามิเตอร์ GET 'การโทรกลับ' ให้กับคำขอนั่นคือชื่อของฟังก์ชันการเรียกกลับ jquery ที่ใช้และควรเพิ่มในการตอบกลับ
BGerrissen

2
ในปี 2559 CORS เป็นมาตรฐานที่ได้รับการสนับสนุนอย่างกว้างขวางเมื่อเทียบกับ JSONP ซึ่งสามารถอธิบายได้ว่าเป็นการแฮกเท่านั้น @joshuarh คำตอบด้านล่างควรเป็นคำตอบที่ต้องการในขณะนี้
Vicky Chijwani

202

JSONP เป็นตัวเลือกที่ดี แต่มีวิธีที่ง่ายกว่า คุณสามารถตั้งค่าAccess-Control-Allow-Originส่วนหัวบนเซิร์ฟเวอร์ของคุณ การตั้งค่าเป็น*จะยอมรับคำขอ AJAX ข้ามโดเมนจากโดเมนใดก็ได้ ( https://developer.mozilla.org/en/http_access_control )

วิธีการทำเช่นนี้จะแตกต่างกันไปในแต่ละภาษาแน่นอน นี่คือใน Rails:

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

ในตัวอย่างนี้การsay_helloกระทำจะยอมรับคำขอ AJAX จากโดเมนใด ๆ และส่งกลับการตอบสนองของ "hello!"

นี่คือตัวอย่างของส่วนหัวที่อาจส่งคืน:

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

ง่ายเหมือนเดิมมันมีข้อ จำกัด บางอย่างของเบราว์เซอร์ ดูhttp://caniuse.com/#feat=cors


12
Jsonp ไม่สนับสนุนโพสต์ใส่และลบ โซลูชันของคุณใช้งานได้ดี
TonyTakeshi

35
ในส่วนหัวของ PHP ("Access-Control-Allow-Origin: *");
SparK

9
@Warrior หากคุณใช้.post()วิธีการของ jQuery คุณจะต้องเปิดใช้งานการสนับสนุนข้ามโดเมนใน jQuery มันทำกับสิ่งนี้: $.support.cors = true.
Friederike

21
สิ่งที่เกี่ยวข้องกับความปลอดภัยของการกำหนดค่าเซิร์ฟเวอร์ในลักษณะนี้คืออะไร?
Jon Schneider

19
จะเป็นการดีกว่าถ้าอนุญาตเฉพาะโดเมนที่คุณต้องการแชร์ข้อมูลด้วยแทนที่จะใช้ wilcard "*"
Sebastián Grignoli

32

คุณสามารถควบคุมสิ่งนี้ได้ผ่านทางส่วนหัว HTTP โดยการเพิ่มAccess-Control-Allow-Originการเข้าถึงการควบคุมอนุญาตให้-แหล่งกำเนิดสินค้าการตั้งค่าเป็น * จะยอมรับคำขอ AJAX ข้ามโดเมนจากทุกโดเมน

การใช้PHPนั้นง่ายมากเพียงแค่เพิ่มบรรทัดต่อไปนี้ลงในสคริปต์ที่คุณต้องการเข้าถึงจากนอกโดเมนของคุณ:

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

อย่าลืมเปิดใช้งานโมดูล mod_headers ใน httpd.conf


คุณบันทึกวันของฉัน
NomanJaved

20

คุณต้องดูนโยบายต้นกำเนิดเดียวกัน :

ในการคำนวณนโยบายต้นกำเนิดเดียวกันเป็นแนวคิดความปลอดภัยที่สำคัญสำหรับภาษาการเขียนโปรแกรมด้านเบราว์เซอร์เช่นจาวาสคริปต์ นโยบายอนุญาตให้สคริปต์ทำงานบนหน้าเว็บที่มีต้นกำเนิดมาจากไซต์เดียวกันเพื่อเข้าถึงวิธีการและคุณสมบัติของกันและกันโดยไม่มีข้อ จำกัด เฉพาะ แต่ป้องกันการเข้าถึงวิธีการและคุณสมบัติส่วนใหญ่ในหน้าต่างๆในไซต์ต่างๆ

เพื่อให้คุณสามารถรับข้อมูลได้จะต้อง:

โปรโตคอลและโฮสต์เดียวกัน

คุณต้องใช้JSONPเพื่อแก้ไขปัญหา


17

ฉันต้องโหลดหน้าเว็บจากดิสก์ภายในเครื่อง "ไฟล์: /// C: /test/htmlpage.html" เรียก "http: //localhost/getxml.php" url และทำสิ่งนี้ในเบราว์เซอร์ IE8 + และ Firefox12 + ใช้ jQuery v1 .7.2 lib เพื่อลดรหัสสำเร็จรูป หลังจากอ่านบทความหลายสิบในที่สุดก็คิดออก นี่คือบทสรุปของฉัน

  • สคริปต์เซิร์ฟเวอร์ (.php, .jsp, ... ) จะต้องส่งคืนส่วนหัวการตอบสนอง http การควบคุมการเข้าถึง - อนุญาต - กำเนิด: *
  • ก่อนที่จะใช้ jQuery ajax ตั้งค่าสถานะนี้ใน javascript: jQuery.support.cors = true
  • คุณสามารถตั้งค่าสถานะหนึ่งครั้งหรือทุกครั้งก่อนใช้ฟังก์ชัน jQuery ajax
  • ตอนนี้ฉันสามารถอ่านเอกสาร. xml ใน IE และ Firefox เบราว์เซอร์อื่น ๆ ที่ฉันไม่ได้ทดสอบ
  • เอกสารตอบกลับอาจเป็นแบบธรรมดา / ข้อความ xml, json หรืออะไรก็ได้

นี่คือตัวอย่างการเรียก jQuery ajax พร้อม sysouts ดีบัก

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
ฉันเขียนคำตอบสำหรับคำถามนี้ที่นี่: การโหลดหน้าข้ามโดเมน HTML ด้วย jQuery AJAX - หน้าสุดท้ายรองรับ https
jherax

สำหรับจุดที่น้อยที่สุด: ใน PHP เพิ่มบรรทัดนี้ในสคริปต์:header("Access-Control-Allow-Origin: *");
T30

1
@ ใครขอบคุณมากสำหรับคำตอบของคุณ คุณช่วยฉันมาก ไชโย
Luis Milanese

10

เป็นความจริงที่ว่านโยบายต้นกำเนิดเดียวกันนั้นป้องกันไม่ให้ JavaScript ทำการร้องขอข้ามโดเมน แต่ข้อกำหนด CORS จะอนุญาตให้คุณเข้าถึง API ประเภทที่คุณต้องการเท่านั้นและได้รับการสนับสนุนจากชุดเบราว์เซอร์หลักในปัจจุบัน

ดูวิธีการเปิดใช้งานการแชร์ทรัพยากรข้ามแหล่งสำหรับไคลเอนต์และเซิร์ฟเวอร์:

http://enable-cors.org/

"การแบ่งปันทรัพยากรต้นกำเนิด (CORS) เป็นข้อกำหนดที่เปิดใช้งานการเข้าถึงข้ามขอบเขตโดเมนอย่างแท้จริงหากคุณให้บริการเนื้อหาสาธารณะโปรดพิจารณาใช้ CORS เพื่อเปิดใช้สำหรับการเข้าถึง JavaScript / เบราว์เซอร์สากล"


9

สิ่งนี้เป็นไปได้ แต่คุณต้องใช้ JSONP ไม่ใช่ JSON ลิงก์ของ Stefan ชี้ให้คุณในทิศทางที่ถูกต้อง หน้า jQuery AJAXมีข้อมูลเพิ่มเติมเกี่ยวกับ JSONP

Remy ชาร์ปมีตัวอย่างรายละเอียดการใช้ PHP


9

ฉันใช้เซิร์ฟเวอร์ Apache ดังนั้นฉันจึงใช้โมดูล mod_proxy เปิดใช้งานโมดูล:

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

จากนั้นเพิ่ม:

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

สุดท้ายส่ง proxy-url ไปที่สคริปต์ของคุณ



5

มีตัวอย่างบางส่วนสำหรับการใช้ JSONP ซึ่งรวมถึงการจัดการข้อผิดพลาด

อย่างไรก็ตามโปรดทราบว่าข้อผิดพลาดเหตุการณ์จะไม่ถูกเรียกเมื่อใช้ JSONP! ดู: http://api.jquery.com/jQuery.ajax/หรือคำขอ jQuery ajax โดยใช้ข้อผิดพลาด jsonp


4

จาก Jquery docs ( ลิงก์ ):

  • เนื่องจากข้อ จำกัด ด้านความปลอดภัยของเบราว์เซอร์คำขอ "Ajax" ส่วนใหญ่อยู่ภายใต้นโยบายต้นทางเดียวกัน คำขอไม่สามารถดึงข้อมูลจากโดเมนโดเมนย่อยหรือโปรโตคอลอื่นได้สำเร็จ

  • คำขอสคริปต์และ JSONP ไม่อยู่ภายใต้ข้อ จำกัด นโยบายกำเนิดเดียวกัน

ดังนั้นฉันจะเอาว่าคุณต้องใช้ jsonp สำหรับคำขอ แต่ไม่ได้ลองด้วยตัวเอง


2

ฉันรู้วิธีแก้ปัญหาของคุณ 3 วิธี:

  1. ก่อนอื่นถ้าคุณมีสิทธิ์เข้าถึงทั้งสองโดเมนคุณสามารถอนุญาตการเข้าถึงสำหรับโดเมนอื่นทั้งหมดโดยใช้:

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

    หรือเพียงแค่โดเมนโดยการเพิ่มรหัสตะโกนไปที่ไฟล์. 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. คุณสามารถขอ ajax ไปยังไฟล์ php ในเซิร์ฟเวอร์ของคุณและจัดการคำขอไปยังโดเมนอื่นโดยใช้ไฟล์ php นี้

  3. คุณสามารถใช้ jsonp ได้เนื่องจากไม่ต้องการการอนุญาต สำหรับสิ่งนี้คุณสามารถอ่านคำตอบ @BGerrissen เพื่อนของเรา

0

สำหรับ Microsoft Azure มันแตกต่างกันเล็กน้อย

Azure มีการตั้งค่า CORS พิเศษที่จำเป็นต้องตั้งค่า โดยพื้นฐานแล้วมันก็เหมือนกันกับเบื้องหลัง แต่การตั้งค่าส่วนหัวที่โจชัวกล่าวถึงจะไม่ทำงาน เอกสาร Azure สำหรับเปิดใช้งานข้ามโดเมนสามารถดูได้ที่นี่:

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

ฉันเล่นกับมันสองสามชั่วโมงก่อนที่จะรู้ว่าแพลตฟอร์มโฮสติ้งของฉันมีการตั้งค่าพิเศษนี้


0

ทำงานได้ตามที่คุณต้องการ:

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 }
});
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.