ajax跨域问题解决方案
今天来记录一下关于ajax跨域的一些问题。以备不时之需。
跨域
同源策略限制
同源策略阻止从一个域上加载的脚本获取或操作另一个域上的文档属性。也就是说,受到请求的 URL 的域必须与当前 Web 页面的域相同。这意味着浏览器隔离来自不同源的内容,以防止它们之间的操作。
解决方式
通常来说,比较通用的有如下两种方式,一种是从服务器端下手,另一种则是从客户端的角度出发。二者各有利弊,具体要使用哪种方式还需要具体的分析。
- 服务器设置响应头
- 服务器代理
- 客户端采用脚本回调机制。
方式一
Access-Control-Allow-Origin 关键字只有在服务器端进行设置才
会生效。也就是说即使再客户端使用
xmlhttprequest.setHeaderREquest('xx','xx');
也不会有什么效果。
正常ajax请求
下面来模拟一下ajax非跨域请求的案例实现。
test1.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>ajax 测试</title>
</head>
<body><input type="button" value="Test" onclick="crossDomainRequest()">
<div id="content"></div>
<script>var xhr = new XMLHttpRequest();var url = 'http://localhost/learn/ajax/test1.php';function crossDomainRequest() {document.getElementById('content').innerHTML = "<font color='red'>loading...</font>";// 延迟执行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></body>
</html>
同级目录下的test1.php内容如下:
<?phpecho "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直接去请求其他网站的数据。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>ajax 测试</title>
</head>
<body><input type="button" value="Test" onclick="crossDomainRequest()">
<div id="content"></div>
<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...</font>";// 延迟执行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></body>
</html>
结果如下:
启用代理模式
刚才的HTML页面,咱们还是用自己的接口:
url = 'http://localhost/learn/ajax/test1.php';
具体如下:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>ajax 测试</title>
</head>
<body><input type="button" value="Test" onclick="crossDomainRequest()">
<div id="content"></div>
<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...</font>";// 延迟执行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></body>
</html>
然后对应的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数据,通过回调的方式传回给客户端。
原生实现
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>ajax 测试</title><script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.8.0.js" type="text/javascript"></script>
</head>
<body>
<input type="text" name="talk" id="talk">
<input type="button" value="Test" id="btn">
<div id="content"></div>
<script type="text/javascript">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></body>
</html>
服务器端test1.php内容如下:
<?php$arr = [1,2,3,4,5,6];
$result = json_encode($arr);
echo "jsonpcallback(".$result.")";?>
需要注意的是最后组装的返回值内容。
来看下最终的代码执行效果。
JQuery方式实现
采用原生的JavaScript需要处理的事情还是蛮多的,下面为了简化操作,决定采用JQuery来代替一下。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>ajax 测试</title><script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.8.0.js" type="text/javascript"></script>
</head>
<body>
<input type="text" name="talk" id="talk">
<input type="button" value="Test" id="btn">
<div id="content"></div><script type="text/javascript">function later_action(msg) {var element = $("<div><font color='green'>"+msg+"</font><br /></div>");$("#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></body>
</html>
相应的,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)。自己玩玩知道有这么个东西好了。维护起来实在是优点麻烦。
参考链接:
Ajax跨域请求: http://justcoding.iteye.com/blog/1366102
服务器端跨域设置: http://blog.sina.com.cn/s/blog_bd26b6d20102vjv6.html
Ajax高级笔记: http://www.cnblogs.com/slowsoul/archive/2013/05/04/3059844.html
ajax跨域问题解决方案相关推荐
- PHP下ajax跨域的解决方案之CORS
PHP下ajax跨域的解决方案之CORS 参考文章: (1)PHP下ajax跨域的解决方案之CORS (2)https://www.cnblogs.com/jkko123/p/6294625.html ...
- 【JS】AJAX跨域-JSONP解决方案(一)
[JS]AJAX跨域-JSONP解决方案(一) 参考文章: (1)[JS]AJAX跨域-JSONP解决方案(一) (2)https://www.cnblogs.com/h--d/p/11470534. ...
- 关于Ajax跨域的解决方案
关于Ajax跨域的解决方案和一些个人理解 Ajax跨域的原因 Ajax跨域的解决方案 Ajax跨域的原因 浏览器限制 跨域(协议.主机名.端口有一个不同就会产生跨域) xhr请求(XMLHttpReq ...
- ajax中cors解决跨域,AJAX 跨域 CORS 解决方案
两种跨域方法 在 Javascript 中跨域访问是比较常见的事情 就像现在比较流行写单页应用,而单页应用在访问 API 的时候就会有跨域的问题 要解决跨域的问题,其实也并不复杂,有两种方案可以选择 ...
- js ajax 跨域问题 解决方案
什么是跨域问题? 跨域问题来源于JavaScript的"同源策略",即只有 协议+主机名+端口号 (如存在)相同,则允许相互访问.也就是说JavaScript只能访问和操作自己域下 ...
- ajax跨越html,ajax跨域的解决方案
什么是跨域 跨域问题产生的原因,是由于浏览器的安全机制,JS只能访问与所在页面同一个域(相同协议.域名.端口)的内容(参考js的同源策略). 但是我们项目开发过程中,经常会遇到在一个页面的JS代码中, ...
- ajax跨域情况解决方案,ajax跨域解决方案.docx
ajax跨域解决方案 ajax跨域解决方案 篇一:使用JSONP解决Ajax跨域访问问题 使用JSONP解决Ajax跨域访问问题 JSONP(JSON with Padding)是JSON的一种&qu ...
- Ajax跨域请求解决方案——jsonp
转自:http://www.cnblogs.com/dowinning/archive/2012/04/19/json-jsonp-jquery.html 1.一个众所周知的问题,Ajax直接请求普通 ...
- Ajax跨域及解决方案
了解跨域之前,我们要了解浏览器的同源策略 同源策略(英文全称 Same origin policy)是浏览器提供的一个安全功能 通俗的理解:浏览器规定,A 网站的 JavaScript,不允许和非同源 ...
最新文章
- servlet生命周期
- WiFi万能钥匙发布iOS4.0新增骚扰电话拦截功能
- Android Studio开发版(debug)和发布版(release)获取SHA1和MD5和SHA256的最原始方法
- Java 8的惰性序列实现
- 对公平席位分配问题的探讨:最大余数法、Q值法和D’Hondt方法及其特例|公平分配原则等
- 安装oracle需要多少内存,针对大型内存配置的 Oracle VM 安装需要更多步骤 (7195262)...
- C++程序代码:类实现——【calculator】计算器程序设计
- IDF 实验室 初探乾坤
- 读取mysql表名称_JAVA动态读取mysql表的字段名索引
- 快速学会普源示波器的调节和使用
- Android 呼叫转移
- “茴”字有几种写法? Java 实现 WebSocket 的方式
- 浅谈LED芯片库存信息化管理
- 云流化技术应用之K12VR云课堂
- python扇贝每日一句api_【扇贝批量添加单词到词库】利用python调用扇贝API (oauth2)...
- 洪灾面前,能抗衡的很少,但能做的很少
- 腾讯云web应用防火墙(WAF)防护设置步骤介绍
- VC版DoEvents/处理事件
- android仿抖音礼物列表实现,Android仿抖音列表效果
- Stanford Large-Scale 3D Indoor Spaces Dataset (S3DIS)