ホームページ >ウェブフロントエンド >jsチュートリアル >Ajax クロスドメインの問題の詳細な図による説明 (コード付き)
今回は、Ajax クロスドメイン問題の詳細な図解説明 (コード付き) をご紹介します。実際のケースを見てみましょう。
クロスドメイン同一生成元ポリシーの制限
同一生成元ポリシーは、あるドメインに読み込まれたスクリプトが別のドメインのドキュメント プロパティを取得または操作することを防ぎます。つまり、要求された URL のドメインは、現在の Web ページのドメインと同じである必要があります。これは、ブラウザがさまざまなソースからコンテンツを分離して、ソース間での操作を防止することを意味します。
ソリューション一般的に、一般的な方法は 2 つあり、1 つはサーバー側からの方法、もう 1 つはクライアントの観点からの方法です。どちらにも長所と短所があり、どちらの方法を使用するかは具体的な分析が必要です。
Access-Control-Allow-Origin キーワードは、サーバー側で設定されている場合にのみ有効になります。つまり、
クライアントxmlhttprequest.setHeaderREquest('xx','xx');
で使用しても効果はありません。 通常のajaxリクエスト
ajaxの非クロスドメインリクエストの実装例をシミュレートしてみましょう。
test1.htmlnbsp;html>
<meta>
<title>ajax 测试</title>
<input>
<p></p>
<script>
var xhr = new XMLHttpRequest();
var url = 'http://localhost/learn/ajax/test1.php';
function crossDomainRequest() {
document.getElementById('content').innerHTML = "<font color='red'>loading...";
// 延迟执行
setTimeout(function () {
if (xhr) {
xhr.open('GEt', url, true);
xhr.onreadystatechange = handle_response;
xhr.send(null);
} else {
document.getElementById('content').innerText = "不能创建XMLHttpRequest对象";
}
}, 3000);
}
function handle_response() {
var container = document.getElementById('content');
if (xhr.readyState == 4) {
if (xhr.status == 200 || xhr.status == 304) {
container.innerHTML = xhr.responseText;
} else {
container.innerText = '不能跨域请求';
}
}
}
</script>
同じディレクトリにあるtest1.PHPの内容は以下の通りです:
<?php echo "It Works."; ?>
クロスドメインリクエスト
今、HTMLファイルとphpファイルは両方とも以下にあります。 Apache コンテナなので、クロスドメイン リクエストはありません。ドメインの場合は、HTML ファイルをデスクトップに置き、再度 PHP データをリクエストすることで、このような「クロスドメイン リクエスト」を作成します。
ブラウザのアドレスバー情報に注意してください
再度アクセスすると、次のエラーメッセージが表示されます。
この場合、一般的な操作は Access-Control-Allow-Origin を設定することです。 
header("Access-Control-Allow-Origin: *");ASPXページの場合は、次のように設定します(Javaも同様です):
Response.AddHeader("Access-Control-Allow-Origin", "*");At this時間です、今の道を訪れてください。
サーバー
この方法は、より一般的に使用され、広く採用されている方法と見なされるべきです。エージェントというとちょっと書きすぎですが、実際には単なるメッセンジャーです。小さな例を挙げてみましょう:
Xiao Ming は 3 年生の Xiao Hon という名前の女の子が好きですが、恥ずかしくて QQ と WeChat ID を尋ねることができません。そこでクラスの女子シャオランに聞いてみた。来て、それを手に入れるのを手伝ってください。したがって、シャオランはエージェントに相当します。シャオミンが直接入手できなかったシャオホンの連絡先情報を入手できるよう協力してください。 この問題を説明するために例を挙げてみましょう。ダイレクトクロスドメインリクエスト
先ほど URL を変更して、ajax が他の Web サイトからデータを直接リクエストできるようにします。
nbsp;html>
<meta>
<title>ajax 测试</title>
<input>
<p></p>
<script>
var xhr = new XMLHttpRequest();
// var url = 'http://localhost/learn/ajax/test1.php';
var url = 'http://api.qingyunke.com/api.php?key=free&appid=0&msg=%E5%93%92%E5%93%92';
function crossDomainRequest() {
document.getElementById('content').innerHTML = "<font color='red'>loading...";
// 延迟执行
setTimeout(function () {
if (xhr) {
xhr.open('GEt', url, true);
xhr.onreadystatechange = handle_response;
xhr.send(null);
} else {
document.getElementById('content').innerText = "不能创建XMLHttpRequest对象";
}
}, 3000);
}
function handle_response() {
var container = document.getElementById('content');
if (xhr.readyState == 4) {
if (xhr.status == 200 || xhr.status == 304) {
container.innerHTML = xhr.responseText;
} else {
container.innerText = '不能跨域请求';
}
}
}
</script>
結果は次のとおりです:
プロキシモードを有効化します
先ほどの HTML ページでは、引き続き独自のインターフェイスを使用します:
url = 'http://localhost/learn/ajax/test1.php';詳細は次のとおりです:
nbsp;html>
<meta>
<title>ajax 测试</title>
<input>
<p></p>
<script>
var xhr = new XMLHttpRequest();
var url = 'http://localhost/learn/ajax/test1.php';
// var url = 'http://api.qingyunke.com/api.php?key=free&appid=0&msg=%E5%93%92%E5%93%92';
function crossDomainRequest() {
document.getElementById('content').innerHTML = "<font color='red'>loading...";
// 延迟执行
setTimeout(function () {
if (xhr) {
xhr.open('GEt', url, true);
xhr.onreadystatechange = handle_response;
xhr.send(null);
} else {
document.getElementById('content').innerText = "不能创建XMLHttpRequest对象";
}
}, 3000);
}
function handle_response() {
var container = document.getElementById('content');
if (xhr.readyState == 4) {
if (xhr.status == 200 || xhr.status == 304) {
container.innerHTML = xhr.responseText;
} else {
container.innerText = '不能跨域请求';
}
}
}
</script>
然后对应的test1.php应该帮助我们实现数据请求这个过程,把“小红的联系方式”要到手,并返回给“小明”。
<?php $url = 'http://api.qingyunke.com/api.php?key=free&appid=0&msg=hello%20world.'; $result = file_get_contents($url); echo $result; ?>
下面看下代码执行的结果。

jsonp方式
JSONP(JSON with Padding) 灵感其实源于在HTML页面中script标签内容的加载,对于script的src属性对应的内容,浏览器总是会对其进行加载。于是:
克服该限制更理想方法是在 Web 页面中插入动态脚本元素,该页面源指向其他域中的服务 URL 并且在自身脚本中获取数据。脚本加载时它开始执行。该方法是可行的,因为同源策略不阻止动态脚本插入,并且将脚本看作是从提供 Web 页面的域上加载的。但如果该脚本尝试从另一个域上加载文档,就不会成功。
实现的思路就是:
在服务器端组装出客户端预置好的json数据,通过回调的方式传回给客户端。
原生实现
nbsp;html>
<meta>
<title>ajax 测试</title>
<script></script>
<input>
<input>
<p></p>
<script>
function jsonpcallback(result) {
for(var i in result) {
alert(i+":"+result[i]);
}
}
var JSONP = document.createElement("script");
JSONP.type='text/javascript';
JSONP.src='http://localhost/learn/ajax/test1.php?callback=jsonpcallback';
document.getElementsByTagName('head')[0].appendChild(JSONP);
</script>
服务器端test1.php内容如下:
<?php $arr = [1,2,3,4,5,6];
$result = json_encode($arr);
echo "jsonpcallback(".$result.")";
?>
需要注意的是最后组装的返回值内容。
来看下最终的代码执行效果。

JQuery方式实现
采用原生的JavaScript需要处理的事情还是蛮多的,下面为了简化操作,决定采用jQuery来代替一下。
nbsp;html>
<meta>
<title>ajax 测试</title>
<script></script>
<input>
<input>
<p></p>
<script>
function later_action(msg) {
var element = $("<p><font color='green'>"+msg+"<br />");
$("#content").append(element);
}
$("#btn").click(function(){
// alert($("#talk").val());
$.ajax({
url: 'http://localhost/learn/ajax/test1.php',
method: 'post',
dataType: 'jsonp',
data: {"talk": $("#talk").val()},
jsonp: 'callback',
success: function(callback){
console.log(callback.content);
later_action(callback.content);
},
error: function(err){
console.log(JSON.stringify(err));
},
});
});
</script>
相应的,test1.php为了配合客户端聊天的需求,也稍微做了点改变。
<?php $requestparam = isset($_GET['callback'])?$_GET['callback']:'callback';
// 青云志聊天机器人接口: http://api.qingyunke.com/api.php?key=free&appid=0&msg=hello
// 接收来自客户端的请求内容
$talk = $_REQUEST['talk'];
$result = file_get_contents("http://api.qingyunke.com/api.php?key=free&appid=0&msg=$talk");
// 拼接一些字符串
echo $requestparam . "($result)";
?>
最后来查看一下跨域的效果吧。

总结
至此,关于简单的ajax跨域问题,就算是解决的差不多了。对我个人而言,对于这三种方式有一点点自己的看法。
服务器设置Access-Control-Allow-Origin的方式适合信用度高的小型应用或者个人应用。
代理模式则比较适合大型应用的处理。但是需要一个统一的规范,这样管理和维护起来都会比较方便。
JSONP方式感觉还是比较鸡肋的(有可能是我经验还不足,没认识到这个方式的优点吧(⊙﹏⊙)b)。自己玩玩知道有这么个东西好了。维护起来实在是优点麻烦。
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
以上がAjax クロスドメインの問題の詳細な図による説明 (コード付き)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。