CORS跨域POST请求并不兼容IE7及以下

很多人以为(包括我之前也是)跨域只需要后端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');
}

绝大多数情况下,我们只需要和onloadonerror打交道,就像下面这样:

xhr.onload = function() {
 var responseText = xhr.responseText;
 console.log(responseText);
 // 继续其它代码
};

xhr.onerror = function() {
  console.log('There was an error!');
};

简单请求

  1. 不发送自定义header(如x-pingother,等)
  2. 只使用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'));
?>

一些笔记:

  1. 当 credentials 设为真时,通配符“*”不能用于’Access-Control-Allow-Origin’
  2. 当进行同步请求时,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

以上代码参考:

  1. How to Send Cross Domain AJAX Request with jQuery
  2. Cross Domain AJAX Request
  3. 利用CORS实现跨域请求

关注我

我的微信公众号:前端开发博客,在后台回复以下关键字可以获取资源。

  • 回复「小抄」,领取Vue、JavaScript 和 WebComponent 小抄 PDF
  • 回复「Vue脑图」获取 Vue 相关脑图
  • 回复「思维图」获取 JavaScript 相关思维图
  • 回复「简历」获取简历制作建议
  • 回复「简历模板」获取精选的简历模板
  • 回复「加群」进入500人前端精英群
  • 回复「电子书」下载我整理的大量前端资源,含面试、Vue实战项目、CSS和JavaScript电子书等。
  • 回复「知识点」下载高清JavaScript知识点图谱

每日分享有用的前端开发知识,加我微信:caibaojian89 交流