今天来记录一下关于ajax跨域的一些问题。以备不时之需。
今天来记录一下关于ajax跨域的一些问题。以备不时之需。
跨域
同源策略限制
同源策略阻止从一个域上加载的脚本获取或操作另一个域上的文档属性。也就是说,受到请求的 URL 的域必须与当前 Web 页面的域相同。这意味着浏览器隔离来自不同源的内容,以防止它们之间的操作。
解决方式
通常来说,比较通用的有如下两种方式,一种是从服务器端下手,另一种则是从客户端的角度出发。二者各有利弊,具体要使用哪种方式还需要具体的分析。
服务器设置响应头
服务器代理
客户端采用脚本回调机制。
方式一
Access-Control-Allow-Origin 关键字只有在服务器端进行设置才
会生效。也就是说即使再客户端使用
xmlhttprequest.setHeaderREquest('xx','xx');
1
1
也不会有什么效果。
正常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内容如下:
<?php
echo "It Works.";
?>
正常ajax请求
跨域请求
刚才是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", "*");
1
1
这时,再次来访问一下刚才的路径。
服务器端跨域设置
服务器代理模式
这种方式应该算是比较常用的,而且被广泛采纳的一个方式了。说代理有点太过于书面化了,其实就是传话儿的。来举个小例子:
小明喜欢三班一个叫小红的女孩儿,但是不好意思去要人家的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';
1
1
具体如下:
<!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.")";
需要注意的是最后组装的返回值内容。
来看下最终的代码执行效果。
JSONP原生跨域实现
JQuery方式实现
采用原生的JavaScript需要处理的事情还是蛮多的,下面为了简化操作,决定采用jQuery来代替一下。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset= www.lxinyul.cc/"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").www.luleu99.com 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("www.wmyl11.com/ /api.php?key=free&appid=0&msg=$talk");
// 拼接一些字符串
echo $requestparam . "($result)";
最后来查看一下跨域的效果吧。
JSONP 跨域实现聊天应用
总结
至此,关于简单的ajax跨域问题,就算是解决的差不多了。对我个人而言,对于这三种方式有一点点自己的看法。
服务器设置Access-Control-Allow-Origin的方式适合信用度高的小型应用或者个人应用。
代理模式则比较适合大型应用的处理。但是需要一个统一的规范,这样管理和维护起来都会比较方便。
JSONP方式感觉还是比较鸡肋的(有可能是我经验还不足,没认识到这个方式的优点吧(⊙﹏⊙)b)。自己玩玩知道有这么个东西好了。维护起来实在是优点麻烦。
今天来记录一下关于ajax跨域的一些问题。以备不时之需。的更多相关文章
- 个人学习记录2:ajax跨域封装
/** * 跨域提交公用方法 * @param param 参数 * @param url 跨域的地址 * @param callFun 回调函数 callFun(data) */ function ...
- ajax跨域问题解决方案
今天来记录一下关于ajax跨域的一些问题.以备不时之需. 跨域 同源策略限制 同源策略阻止从一个域上加载的脚本获取或操作另一个域上的文档属性.也就是说,受到请求的 URL 的域必须与当前 Web 页面 ...
- Ajax跨域访问wcf服务中所遇到的问题总结。
工具说明:vs2012,sql server 2008R2 1.首先,通过vs2012建立一个wcf服务项目,建立好之后.再新开一个vs2012 建立web项目,通过jQuery的ajax方法访问服务 ...
- php中ajax跨域请求---小记
php中ajax跨域请求---小记 前端时间,遇到的一个问题,情况大约是这样: 原来的写法: 前端js文件中: $.ajax({ type:'get', url:'http://wan.xxx.c ...
- 总结Ajax跨域调用问题
原文:http://blog.csdn.net/wangxiaohu__/article/details/7294842 (一):动态脚本注入的方法.即在页面中动态生成<script>脚本 ...
- ajax跨域请求的解决方案
一直打算改造一下自己传统做网站的形式. 我是.Net程序员,含辛茹苦数年也没混出个什么名堂. 最近微信比较火, 由于现在大环境的影响和以前工作的总结和经验,我打算自己写一个数据,UI松耦合的比较新潮的 ...
- WebApi 自定义过滤器实现支持AJAX跨域的请求
我想关于此类话题的文章,大家一搜铺天盖地都是,我写此文的目的,只是对自己学习过程的记录,能对需要的朋友有所帮助,也百感荣幸!!!废话不多说,直接上代码! 客户端:很简单的AJAX请求 <html ...
- 有关Ajax跨域请求的解决方案
前言 最近博主在赶项目进度.所以微信二次开发那边的博文一直没有更新.后续时间会慢慢记录这个学习历程的.来年公司要开发微信小程序.到时也会记录一下历程. 闲话少说,今天在工作中遇到了SpringMVC接 ...
- AJAX跨域完全讲解
AJAX跨域完全讲解 今天在慕课网上学习了AJAX跨域完全讲解:https://www.imooc.com/learn/947 我在收集AJAX面试题的时候其实就已经有过AJAX跨域的问题的了,当时候 ...
随机推荐
- Mysql异常_01_ 誓死登进mysql_Can't connect to MySQL server on 'localhost' (10061)
现象:打开cmd,输入命令:mysql -uroot -p 回车之后,输入密码,结果进不去mysql,并且抛出异常 异常:Can't connect to MySQL server on 'local ...
- BEC listen and translation exercise 40
However, recently there's been more and more interest in the development of ostrich farming in other ...
- 设计模式 之 《观察者模式 (Observer)》
#ifndef __OBSERVER_MODEL__ #define __OBSERVER_MODEL__ #include <string> #include <iostream& ...
- 继续学习C:运算符
" / " 两整数相除,结果为整数,有一方是实数形式,结果保留小数 " % " 求余运算符要求两侧均为整型数据, 数值取余,符号与被除数一 ...
- LiveMediaStreamer
LiveMediaStreamer is an open source multimedia framework that allows the manipulation of multiple au ...
- ACM学习历程—HDU 5534 Partial Tree(动态规划)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5534 题目大意是给了n个结点,让后让构成一个树,假设每个节点的度为r1, r2, ...rn,求f(x ...
- 寻找总和为n的连续子数列之算法分析
看到有这么道算法题在博客园讨论,算法eaglet和邀月都已经设计出来了,花了点时间读了下,学到点东西顺便记录下来吧. 题目是从1...n的数列中,找出总和为n的连续子数列. 这里先设好算法中需要用到的 ...
- 【转】 Pro Android学习笔记(三九):Fragment(4):基础小例子-续
目录(?)[-] Step 3实现简介显示类DetailFragment 创建实例 编写所需的生命周期代码 Step 4实现showDetailint index如何管理fragment fragme ...
- ios判断是否为iphone6或iphone6plus代码
转自:http://blog.csdn.net/lvxiangan/article/details/45288505 #define IS_IPAD (UI_USER_INTERFACE_IDIOM( ...
- 关于Confusion Matrix
from sklearn.metrics import confusion_matrixy_true = [2, 0, 2, 2, 0, 1]y_pred = [0, 0, 2, 2, 0, 2]pr ...