JavaScript跨域资源请求(CORS)解决方案
跨域:当协议、主域名、子域名、端口号中任意一个不相同时都不算同一个域,而在不同域之间请求数据即为跨域请求。解决方法有以下几种(如有错误欢迎指出)以请求图片url为例:
1.通过XMLHttpRequest对象实现(IE10以下不支持)
XMLHttpRequest2.0已经实现了对CORS的原生支持,只需要在访问资源的时候使用绝对URL即可,需要在服务器端将头信息“Access-Control-Origin"设为”*“或当前域名的地址:
html&javascript:
<button id="btn">load</button>
<div id="process"></div>
<div id="img"></div> <script>
var btn = document.getElementById('btn'),
pro = document.getElementById('process'),
pic = document.getElementById('img'); btn.onclick = function() { var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() { if(xhr.readyState == 4 && xhr.status == 200){
var img = document.createElement('img');
img.src = JSON.parse(xhr.responseText).src;
pic.appendChild(img);
}
}
xhr.open('GET','http://127.0.0.1:8085/AJAX/ajax/server.php',true);
xhr.send(null);
}
</script>
这个例子是在本地测试的,html文件所在的位置是localhost:8085下,虽然127.0.0.1也是指的localhost,但他们也不是同一个域,可以利用这两个地址来模拟跨域请求。
php:
<?php
header("Content-Type:text/plain");
header("Access-Control-Allow-Origin:http://localhost:8085");//设置头部,不设置的话请求会被拒绝
echo '{"src":"http://www.pinkbluecp.cn/face_alignment/img/picture.jpg"}';
?>
post请求也差不多:
btn.onclick = function() {
if(typeof XMLHttpRequest != 'undefined'){
var xhr = new XMLHttpRequest();
}else if(typeof ActiveXObject != 'undefined'){
var xhr = new ActiveXObject("Microsoft.XMLHTTP");
} xhr.onreadystatechange = function() {
console.log(1)
if(xhr.readyState == 4 && xhr.status == 200){
console.log(2)
pic.innerHTML = xhr.responseText;
}
}
xhr.open('POST','http://127.0.0.1:8085/AJAX/ajax/server.php',true);
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); //需要设置下头部
var str = 'active=login';
xhr.send(str);
php
<?php
header("Content-Type:text/plain");
header("Access-Control-Allow-Origin:http://localhost:8085"); if($_POST['active'] == 'login'){
echo 'success';
}else {
echo "error";
}
?>
发送数据需要设置一下头部的Content-Type字段。
2.IE(8-10)中实现CORS:
IE8中引入了XDomainRequest对象,该对象和XHR相似,但它能实现安全可靠的跨域通信,不过在IE11中已经无法使用了。
var btn = document.getElementById('btn'),
pro = document.getElementById('process'),
pic = document.getElementById('img'); btn.onclick = function() {
var xhr = new XDomainRequest();
xhr.onload = function() {
var img = document.createElement('img');
console.log(xhr.responseText)
// img.src = JSON.parse(xhr.responseText).src;
img.src = xhr.responseText;
console.log(img.src);
pic.appendChild(img);
};
xhr.onerror = function() { //XDR无法确定响应状态,需要添加onerror来检测错误
alert("Error!");
}
xhr.open('GET','http://127.0.0.1:8085/AJAX/ajax/server.php'); //该对象的的请求都是异步,没有第三个参数
xhr.send(null);
}
XDR与XHR不同之处在于:
a. cookie不会随请求发送,也不会随响应返回
b. 只能设置请求头中的Content-Type字段
c. 不能访问响应头部信息
d. 只支持GET和POST请求
两者的方法也略有不同,XDR的open方法只有异步一种状态,所以只要传两个参数method和url,在请求返回之后会触发load事件,但无法获取响应状态码,所以想判断请求是否成功只能添加error事件。它也可以和XHR一样添加超时。
关于XDR的post请求,虽然js高编上有介绍,但是在多次尝试后发现已经行不通了,高编上说XDR有专门的属性contentType来设置请求头信息,但在浏览其中会报错:
无法进行设置contentType的操做,后来查阅了一下这篇博客,貌似XDR已经无法在设置请求头了,详情可以去看原博。
3. 实现跨浏览器的CORS
js高编上有一段实现跨浏览器的CORS实现函数:
<button id="btn">load</button>
<div id="process"></div>
<div id="img"></div> <script>
var btn = document.getElementById('btn'),
pic = document.getElementById('img'); btn.onclick = function() {
console.log(1);
var xhr = createCORS('GET','http://127.0.0.1:8085/AJAX/ajax/server.php');
if(xhr){
console.log(2)
xhr.onload = function(){
console.log(3)
var img = document.createElement('img');
img.src = xhr.responseText;
pic.appendChild(img);
};
xhr.onerror = function() {
alert("Error");
};
xhr.send(null);
}
} function createCORS(method,url){ //参考js高编
console.log('fun')
var xhr = new XMLHttpRequest();
if('withCredentials' in xhr){ //检测是否含有凭据属性
xhr.open(method,url,true);
}else if(typeof XDomainRequest != 'undefined'){ //兼容ie
xhr = new XDomainRequest();
xhr.open(method,url);
}else {
xhr = null;
}
return xhr;
}
</script>
除了IE10-外所有浏览器都有withCredentials属性,所以可以根据这个属性来判断是否支持XMLHttpRequest2.0.
4.图片Ping
图片Ping就是利用图片的src可以使用跨域资源的特性来实现,但是只能实现简单的单向请求,在img的src中传入一个其他域的url并附带一些参数。
5.JSONP
JSONP和图片Ping很相似,也是利用script标签中的链接不受同源限制可以向不同域传递信息,但它传递的是一个已经存在的回调函数,服务器接收到后,将响应数据传入该回调函数并执行该函数从而达到获取数据的目的。
先来看下<script>标签中传入src得到的是什么:
<script src="test.txt"></script>
在src中传入一个文本文件
浏览器中报语法错误,hello world这个变量未定义,服务器响应的数据就时test.txt的内容,而script把这段纯文本当作js代码来解析,当在test.txt中将这段文字加上单引号后:
浏览器不报错了,因为把它当作字符串来解析了。现在把链接换成一个php文件:
php
<?php
echo "Hello World!";
?>
结果一样,浏览器同样也会报错,加上引号后同样也不报错,如果这时服务器端返回的是一个函数名,而该页面正好又有一个同名函数会怎样:
php:
<?php
echo "callback('hello world')";
?>
html
<body>
<script>
function callback(res){
alert(res);
}
</script>
<script src="jsonp.php"></script>
</body>
结果:
callback函数被执行了,因为后台的响应数据被script标签当作js代码执行了,所以这就能理解jsonp的原理了,利用这个回调函数可以获得后台传来的数据:
html:
<body>
<script>
function jsonp(res){
for(var i in res){
console.log("key:"+i+";value:"+res[i]);
}
}
</script>
<script src="jsonp.php?callback=jsonp"></script> //可动态创建
</body>
php:
<?php
$str = '{"name":"Lee","age":20}';
$callback = $_GET['callback'];
echo $callback."($str)";
?>
上面一个简单的例子展示了jsonp如何用回调函数获取服务器响应的json数据:
JSONP的有点在于可以访问到服务器的响应文本,不过缺点就是要从其他域加载代码执行,必须要保证其他域的安全性,不然可能响应信息中会附带恶意脚本,还有一点就是无法确定请求是否失败,即使失败也不会有提示。
6.iframe跨域
iframe跨域与jsonp相似,也利用了src不受同源限制的特性。当A域下的x.html页面要访问B域下的y.html中的信息可以通过A域下的z.html页面作为代理来获取信息:
x.html:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
</head> <body>
<iframe src="http://127.0.0.1:8085/AJAX/ajax/proxya.html" style="display: none"></iframe>
<p id="getText"></p>
<script>
function callback(text){
text = JSON.parse(decodeURI(text));
document.getElementById("getText").innerHTML= '姓名:' + text.name + '; 年龄:' + text.age;
}
</script>
</body>
</html>
y.html:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
</head> <body>
<iframe id="myfarme" src="###"></iframe>
<script>
window.onload = function(){
var text = '{"name":"cheng","age":22}'; //存储一个json格式的数据
document.getElementById('myfarme').src="http://localhost:8085/AJAX/ajax/proxyb.html?content="+encodeURI(text); //将数据传个代理页面处理,此时src中的地址不受同源限制,与jsonp相似
}
</script>
</body>
</html>
z.html:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script>
window.onload = function(){
var text = window.location.href.split('=')[1]; //通过分解url获取y.html传来的参数
top.callback(text); //调用x.html的callback函数
}
</script>
</head> <body>
</body>
</html>
JavaScript跨域资源请求(CORS)解决方案的更多相关文章
- 004. 前端跨域资源请求: JSONP/CORS/反向代理
1.什么是跨域资源请求? https://www.cnblogs.com/niuli1987/p/10252214.html 同源: 如果两个页面的协议,端口(如果有指定)和域名都相同,则两个页面具有 ...
- JSONP、图片Ping、XMLHttpRequest2.0等跨域资源请求(CORS)
跨域:当协议.主域名.子域名.端口号中任意一个不相同时都不算同一个域,而在不同域之间请求数据即为跨域请求.解决方法有以下几种(如有错误欢迎指出)以请求图片url为例: 1.通过XMLHttpReque ...
- .net MVC下跨域Ajax请求(CORS)
二.CROS (Cross-origin Resource Sharing) CROS相当于一种协议,由浏览器.服务端共同完成安全验证,进行安全的跨域资源共享.对于开发人员来说就跟在本站AJAX请求一 ...
- 跨域资源请求(除jsonp以外)的方法
---------------------------------------------------------------------------------------------------- ...
- JavaScript跨域调用、JSONP、CORS与ASP.NET Web API[共8篇]
[第1篇] 同源策略与JSONP 浏览器是访问Internet的工具,也是客户端应用的宿主,它为客户端应用提供一个寄宿和运行的环境.而这里所说的应用,基本是指在浏览器中执行的客户端JavaScript ...
- 跨域资源共享(CORS)在ASP.NET Web API中是如何实现的?
在<通过扩展让ASP.NET Web API支持W3C的CORS规范>中,我们通过自定义的HttpMessageHandler自行为ASP.NET Web API实现了针对CORS的支持, ...
- jsonp实现跨域资源访问
平时项目中处理ajax跨域资源请求时,例如www.example2.com上的某个页面要请求www.example1.com的数据,我们使用得较多的是jsonp方式.jsonp通过JavaScript ...
- thinkphp,javascript跨域请求解决方案
javascript跨域请求解决方案 前言 对于很多前端或者做混合开发的同学,我们难免会遇到跨域发起请求业务,比如A站点向B站点请求数据等等.由于最近要做一个站点集群的项目,所以具体业务要求很多个站点 ...
- 从零开始学 Java - Spring MVC 实现跨域资源 CORS 请求
论职业的重要性 问:为什么所有家长都希望自己的孩子成为公务员? 答:体面.有权.有钱又悠闲. 问:为什么所有家长都希望自己的孩子成为律师或医生? 答:体面.有钱.有技能. 问:为什么所有家长都不怎么知 ...
随机推荐
- gulp安装简介
1 全局安装gulp:npm install -g gulp 2 在项目根目录中,安装项目的开发依赖:npm install --save-dev gulp 2.1 根据gulpfile.js中的依赖 ...
- nodejs 静态文件服务器
https://cnodejs.org/topic/4f16442ccae1f4aa27001071 http://blog.csdn.net/zhangxin09/article/details/8 ...
- docker异常处理
Error running DeleteDevice dm_task_run failed重启docker即可 Error starting daemon: error initializing gr ...
- 继承Application以实现全局资源共享
原文地址:http://www.cnblogs.com/Dentist/p/Mr_Dentist_.html 每个程序运行时会创建一个Application类的对象且仅有一个.在app结束时这个App ...
- Logstash 2.0.0 beta2 发布,开源日志管理
Logstash 是一个应用程序日志.事件的传输.处理.管理和搜索的平台.你可以用它来统一对应用程序日志进行收集管理,提供 Web 接口用于查询和统计. Logstash 现在是 ElasticSea ...
- asp.net定时任务
我们这边使用的定时任务框架是Quartz.Net,可以实现异常灵活的定时任务,开发人员只要编写少量的代码就可以实现“每隔一小时执行”.每天22点执行,每月18日下午执行等等各种定时任务. Quartz ...
- Puppet master nginx 扩展提升性能(puppet自动化系列4)
puppet使用SSL(https)协议来进行通讯,默认情况下,puppet server端使用基于Ruby的WEBRick HTTP服务器.由于WEBRick HTTP服务器在处理agent端的性能 ...
- bzoj4403
组合数学 我好菜啊 想到dp去了... 事实上对于固定长度的数列,我们只用考虑选了哪些数就行了,所以这个就是$C(n+m-1,m-1)$ 也就是$n$个数,划分成$m$段且允许空的方案数 然后变成$\ ...
- ES6学习之Proxy
定义:“代理器”,用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程.可以对外界的访问进行过滤和改写. 语法: va ...
- SpringMVC 利用@ResponseBody注解返回Json时,出现406 not acceptable 错误的解决方法。
1 在RequestMapping中加入produces属性如: @RequestMap(value="/path",produces="application/json ...