背景
最近和hbb在写一个项目,采用前后端分离的模式。我写接口,hbb写前端。接口采用json的格式进行数据交互,前端和后端放在了不同的服务器上,一开始调试的时候就遇上了问题。
问题
前端POST数据到接口时,出现问题。
Google Chrome的提示:
XMLHttpRequest cannot load http://weafung.com/index.php/. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.
Mozilla Firefox给出了更直观的提示:
已拦截跨源请求:同源策略禁止读取位于 http://weafung.com/index.php/ 的远程资源。(原因:CORS 头缺少 'Access-Control-Allow-Origin')。
解决
知道哪里出现问题后就要解决,首先了解下CORS。
什么是CORS?
来自维基百科的解释: 跨来源资源共享 - 维基百科,自由的百科全书
跨来源资源共享(CORS)是一份浏览器技术的规范,提供了 Web 服务从不同网域传来沙盒脚本的方法,以避开浏览器的同源策略,是 JSONP 模式的现代版。与 JSONP 不同,CORS 除了 GET 要求方法以外也支持其他的 HTTP 要求。用 CORS 可以让网页设计师用一般的 XMLHttpRequest,这种方式的错误处理比 JSONP 要来的好。另一方面,JSONP 可以在不支持 CORS 的老旧浏览器上运作。现代的浏览器都支持 CORS。
解决过程
在大概了解了CORS之后,初步搜索到大部分的解决方案是在PHP中添加header头:
header("Access-Control-Allow-Origin: *");
添加、测试,现在报错变了:
Google Chrome:
XMLHttpRequest cannot load http://weafung.com/index.php/. Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.
Mozilla Firefox:
已拦截跨源请求:同源策略禁止读取位于 http://weafung.com/index.php/ 的远程资源。(原因:来自 CORS 预检通道的 CORS 头 'Access-Control-Allow-Headers' 的令牌 'content-type' 无效)。
那我再加条header试试?
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: *");
继续失败,还是一样的错误。
在参考 Mozilla Documentation 后发现:Access-Control-Allow-Origin
是支持*
,而在Access-Control-Allow-Headers
部分却没有提到支持*
通配符。
再来:
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept");
咦,好像成功了!!!
解决方法
方法一:在PHP中添加两条header语句
header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept");
方法二:使用来自stackoverflow的cors方法
function cors() { // Allow from any origin if (isset($_SERVER['HTTP_ORIGIN'])) { // Decide if the origin in $_SERVER['HTTP_ORIGIN'] is one // you want to allow, and if so: header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}"); header('Access-Control-Allow-Credentials: true'); header('Access-Control-Max-Age: 86400'); // cache for 1 day } // Access-Control headers are received during OPTIONS requests if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') { if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) header("Access-Control-Allow-Methods: GET, POST, OPTIONS"); if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}"); } }
方法三:不需要修改PHP的解决办法,使用代理或反向代理
具体请参考:CORS 跨域问题 - Chs97's Blog
Weafung原创