這次帶給大家ajax跨域問題的圖文詳解(附程式碼),ajax跨域問題的注意事項有哪些,下面就是實戰案例,一起來看一下。
跨網域
同源策略限制
#同源策略阻止從一個網域上載入的腳本取得或操作另一個域上的文件屬性。也就是說,受到請求的 URL 的網域必須與目前 Web 頁面的網域相同。這意味著瀏覽器隔離來自不同來源的內容,以防止它們之間的操作。
解決方式
通常來說,比較通用的有以下兩種方式,一種是從伺服器端下手,另一種則是從客戶端的角度出發。二者各有利弊,具體要使用哪一種方式還需要具體的分析。
伺服器設定回應頭
伺服器代理程式
用戶端採用腳本回呼機制。
方式一
Access-Control-Allow-Origin 關鍵字只有在伺服器端設定時才
會生效。也就是說即使再客戶端使用
xmlhttprequest.setHeaderREquest('xx','xx');
也不會有什麼效果。
正常ajax請求
下面來模擬ajax非跨域請求的案例實作。
test1.html
nbsp;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。 格式: Access-Control-Allow-Origin: domain.com/xx/yy.*如果知道客戶端的網域或要求的固定路徑,則最好是不使用萬用字元的方式,來進一步保證安全性。如果不確定,那就是用*通配符好了。 後端開發語言為PHP的時候可以再文件開始處這麼設定:header("Access-Control-Allow-Origin: *");如果是ASPX頁面的話,要這麼設定(Java與之類似):
Response.AddHeader("Access-Control-Allow-Origin", "*");這時,再來訪問剛才的路徑。 #這種方式應該算是比較常用的,而且廣受採納的一個方式了。說代理有點太過於書面化了,其實就是傳話兒的。來舉個小例子:小明喜歡三班一個叫小紅的女孩兒,但是不好意思去要人家的QQ,微訊號。然後就托和自己班的女生–小蘭。來幫自己去要。所以小蘭就相當於一個代理。幫助小明取得原本不能直接取得的小紅的聯絡方式。 下面來舉個例子來說明這個問題。
直接的跨域請求
修改一下剛才的URL即可,讓ajax直接去請求其他網站的資料。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中文網其他相關文章!