跨域jQuery AJAX请求PHP报错:Access-Control-Allow-Origin含多值
最近我做了一个加载大量数据的无限滚动页面,前端用jQuery向不同域名的PHP服务器发起AJAX请求——因为跨域的原因,必须配置跨域访问控制头,过程中踩了两个典型的跨域坑,分享下解决思路:
第一个错误:请求头未被允许
一开始没加跨域头的时候,浏览器直接报错:
Request header field X-Requested-With is not allowed by Access-Control-Allow-Headers in preflight response.
原因很直观:jQuery的AJAX请求默认会携带X-Requested-With请求头,但服务器的预请求(OPTIONS)响应里没有声明允许这个头,所以被浏览器拦截了。
第二个错误:Allow-Origin头多值冲突
我赶紧在PHP文件里加了跨域头,结果又出现新的错误:
Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header contains multiple values 'domain, *', but only one is allowed. Origin 'domain' is therefore not allowed access.
当时的服务端PHP代码:
header('Access-Control-Allow-Origin: https://di.community'); header('Access-Control-Allow-Headers: X-Requested-With'); $start = $_GET['start']; echo json_encode(array_slice($tokenData, $start, 500));
客户端jQuery代码:
$.ajax({ if (working == false) { working = true; type: "GET", url: "serverdomain/data.php?start="+start, processData: false, contentType: "application/json", data: '', success: function(r) { r = JSON.parse(r) start += 500; setTimeout(function() { working = false; }, 100) }, error: function(r) { console.log("Something went wrong!"); } } });
我特意指定了允许的域名https://di.community,没敢用*通配符,结果浏览器却说Access-Control-Allow-Origin有多个值。折腾了半天才发现:服务器的.htaccess文件里已经配置过一次Access-Control-Allow-Origin了!PHP代码里加的头和.htaccess里的头重复,导致返回给浏览器的响应里出现了两个相同的头,直接触发了错误。
最终解决方法
找到.htaccess里的跨域配置,要么删掉重复的Access-Control-Allow-Origin行,要么统一在PHP代码里处理跨域头——核心就是确保整个响应里只有一个Access-Control-Allow-Origin值,并且严格匹配我需要允许的域名。
另外提个小优化:客户端代码里success回调的JSON.parse(r)其实可以去掉,只要给AJAX请求加上dataType: 'json',或者服务器返回正确的Content-Type: application/json头,jQuery会自动解析JSON数据,不用手动处理。
内容的提问来源于stack exchange,提问作者Joren Broekema

