很多人以为(包括我之前也是)跨域只需要后端Apach返回的标头中Header set Access-Control-Allow-Origin: *”,就可以放心的使用,今天再跟大家说一次,这个CORS(跨域资源共享)的方案在POST下并不兼容IE7及以下,IE8-IE9则需要使用window.XDomainRequest.来兼容。
比较常用的跨域有jsonp和cors,本文将围绕这两个点来展开。
使用JSONP
虽然jsonp可以支持跨域ajax请求,但是jsonp只支持GET的方式,并不支持post方式,当使用表单发送数据或者数据量较大和安全性较高要求的情况下,你就只能使用post方式了。
$.ajax({ url : "http://top.qdkfweb.cn/cross-domain-cors/jsonp.php", dataType:"jsonp", }); function mycallback(data) { alert("Here: "+data.name); }
jsonp.php 的响应:
mycallback({"name":"Ravishanker","age":32,"location":"India"})
如果要自动处理函数,可以使用下面的方法。在这种情况下,你不需要有任何额外的功能。您可以在成功回调中获得服务器响应。
$.ajax({ url : "http://top.qdkfweb.cn/cross-domain-cors/jsonp.php", dataType:"jsonp", jsonp:"mycallback", success:function(data) { alert("Name:"+data.name+"nage:"+data.age+"nlocation:"+data.location); } });
<?php $callback ='mycallback'; if(isset($_GET['mycallback'])) { $callback = $_GET['mycallback']; } $arr =array(); $arr['name']="Ravishanker"; $arr['age']=32; $arr['location']="India"; echo $callback.'(' . json_encode($arr) . ')'; ?>
使用CORS
设置标头
// PHP
header("Access-Control-Allow-Origin: *");
// Apache (.htaccess)
Header set Access-Control-Allow-Origin "*"
预处理
function createCORSRequest(method, url) { var xhr = new XMLHttpRequest(); if ("withCredentials" in xhr) { // "withCredentials"属性是XMLHTTPRequest2中独有的 xhr.open(method, url, true); } else if (typeof XDomainRequest != "undefined") { // 检测是否XDomainRequest可用 xhr = new XDomainRequest(); xhr.open(method, url); } else { // 看起来CORS根本不被支持 xhr = null; } return xhr; } var xhr = createCORSRequest('GET', url); if (!xhr) { throw new Error('CORS not supported'); }
绝大多数情况下,我们只需要和onload
及onerror
打交道,就像下面这样:
xhr.onload = function() { var responseText = xhr.responseText; console.log(responseText); // 继续其它代码 }; xhr.onerror = function() { console.log('There was an error!'); };
简单请求
- 不发送自定义header(如x-pingother,等)
- 只使用GET、POST或header的方法
<script type="text/javascript"> // Using jQuery $.get("http://www.example.org/ajax.php").done(function (data) { console.log(data); }); // Using XMLHttpRequest var xhr = new XMLHttpRequest(); xhr.open("GET", "http://www.example.org/ajax.php", true); xhr.onload = function () { console.log(xhr.responseText); }; xhr.send(); </script>
widthCredentials
默认情况下,非同一来源的请求,浏览器不会发送凭据(如HTTP cookies,HTTP认证和客户端的SSL证书)。如果有需要则需要在设置XMLHttpRequest对象时加一个特定的属性调用。
<script type="text/javascript"> // Using jQuery $.ajax({ xhrFields: { withCredentials: true }, type: "GET", url: "http://www.example.org/ajax.php" }).done(function (data) { console.log(data); }); // Using XMLHttpRequest var xhr = new XMLHttpRequest(); xhr.open("GET", "http://www.example.org/ajax.php", true); xhr.withCredentials = true; xhr.onload = function () { console.log(xhr.responseText); }; xhr.send(); </script>
后端响应
<?php // http://www.example.org/ajax.php if (!isset($_SERVER['HTTP_ORIGIN'])) { // This is not cross-domain request exit; } $wildcard = FALSE; // Set $wildcard to TRUE if you do not plan to check or limit the domains $credentials = FALSE; // Set $credentials to TRUE if expects credential requests (Cookies, Authentication, SSL certificates) $allowedOrigins = array('https://qdkfweb.cn', 'http://jsfiddle.net'); if (!in_array($_SERVER['HTTP_ORIGIN'], $allowedOrigins) && !$wildcard) { // Origin is not allowed exit; } $origin = $wildcard && !$credentials ? '*' : $_SERVER['HTTP_ORIGIN']; header("Access-Control-Allow-Origin: " . $origin); if ($credentials) { header("Access-Control-Allow-Credentials: true"); } header("Access-Control-Allow-Methods: POST, GET, OPTIONS"); header("Access-Control-Allow-Headers: Origin"); header('P3P: CP="CAO PSA OUR"'); // Makes IE to support cookies // Handling the Preflight if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') { exit; } // Response header("Content-Type: application/json; charset=utf-8"); echo json_encode(array('status' => 'OK')); ?>
一些笔记:
- 当 credentials 设为真时,通配符“*”不能用于’Access-Control-Allow-Origin’
- 当进行同步请求时,Gecko 11.0 (Firefox 11.0 / Thunderbird 11.0 / SeaMonkey 2.8) 不再支持使用withcredentials属性
浏览器支持:
Chrome 3+, Firefox 3.5+, IE 10+, Opera 12+, Safari 4+
兼容IE8的插件
https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest
- 1.只能是GET or POST请求,在使用post时,数据总是发送一个 Content-Type 为text/plain的
- 2.只能是HTTP或者HTTPS,并且双方的协议需要一致
- 3.总是使用异步请求
引入插件
<script type=’text/javascript’ src=”http://cdnjs.cloudflare.com/ajax/libs/jquery-ajaxtransport-xdomainrequest/1.0.1/jquery.xdomainrequest.min.js”></script>
var contentType ="application/x-www-form-urlencoded; charset=utf-8"; if(window.XDomainRequest) //for IE8,IE9 contentType = "text/plain"; $.ajax({ url:"http://top.qdkfweb.cn/cross-domain-cors/post.php", data:"name=Ravi&age=12", type:"POST", dataType:"json", contentType:contentType, success:function(data) { alert("Data from Server"+JSON.stringify(data)); }, error:function(jqXHR,textStatus,errorThrown) { alert("You can not send Cross Domain AJAX requests: "+errorThrown); } });
post.php代码
<?php header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS'); if(isset($HTTP_RAW_POST_DATA)) { parse_str($HTTP_RAW_POST_DATA,$arr); $arr['extra']='1.POST Request from qdkfweb.cn'; echo json_encode($arr); } else { $_POST['extra']='2.POST Request from qdkfweb.cn'; echo json_encode($_POST); } ?>
网上太多的跨域解决方案了,我比较常用的就属JSONP和CORS了,对于IE系列的浏览器兼容,提交数据推荐使用iframe+form的方式,也即window.name的方式,你可以看我前面的一篇文章里面有提供的一个windowname的插件,后面将介绍一下iframe+表单的方式,也补补一下相关知识。
http://friedcell.si/js/jQuery.windowName/jQuery.windowName.plugin.js
以上代码参考: