前端程序使用extjs写,在本地测试,发送请求到服务器时,发现存在跨域的问题,cookie也没有set成功,因而乎在这里整理一下解决过程javascript
因为篇幅较长,不想看解决过程的能够翻到最后看总结
1.跨域容许
2.客户端没法携带跨域cookie
3.由于加了withCredentials报文头,但是客户端不知道服务器允不容许报的错
4.因为客户端不知道服务端是否容许POST请求而报的错php
假设个人服务器IP是120.111.111.123html
# 本地的html
# index.html
<html> <head> <meta charset="utf8"> </head> <body> <input type="button" onclick="request()" value="请求"> </body> <script type="text/javascript" src="./ext-all.js"></script> <script type="text/javascript"> function request(){ Ext.Ajax.request({ url: 'http://120.111.111.123/setcookie.php', method: 'POST', params: { 'text': 'hello world' }, success: function(transport){ // do something }, failure: function(transport){ alert("Error: " - transport.responseText); } }); } </script> </html>
#服务器的php文件
#path setcookie.php
<?php session_start(); ?>
点击“请求”按钮,发送请求后发现js报错前端
XMLHttpRequest cannot load http://120.111.111.123/setcookie.php. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
报这个错就说明咱们跨域了,不在容许的访问源,因而乎我在服务的setcookie.php加入header('Access-Control-Allow-Origin:*');
容许全部源java
<?php session_start(); header('Access-Control-Allow-Origin:*'); // 功能... // ...
而后又报错python
XMLHttpRequest cannot load http://120.111.111.123/setcookie.php. Request header field X-Requested-With is not allowed by Access-Control-Allow-Headers in preflight response.
此次的报错是由于,在跨域的时候,extjs不会直接发post请求,而是先发送一个option请求,看看服务器容许什么访问头(好比是否是容许post请求),验证成功后才会发送真正的请求shell
#用谷歌的开发者工具抓的option报文 OPTIONS /setcookie.php HTTP/1.1 Host: 120.111.111.123 Connection: keep-alive Pragma: no-cache Cache-Control: no-cache Access-Control-Request-Method: POST Origin: null User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Access-Control-Request-Headers: x-requested-with Accept: */* Accept-Encoding: gzip, deflate, sdch Accept-Language: zh-CN,zh;q=0.8
接下来,咱们只要发送咱们容许什么请求头就好了跨域
#path /setcookie.php session_start(); header('Access-Control-Allow-Origin:*'); header('Access-Control-Allow-Methods:OPTIONS, GET, POST'); // 容许option,get,post请求 header('Access-Control-Allow-Headers:x-requested-with'); // 容许x-requested-with请求头 header('Access-Control-Max-Age:86400'); // 容许访问的有效期 // 功能... // ...
继续测试咱们的新功能,成功的解决了跨域问题bash
but,cookie没有“设置成功”。而之因此没有“设置成功”,是由于cookie存在本地,可是每一个cookie都有一个domain,当你本地的cookie中存在你当前访问的域时,才会被带过去,而个人index.html文件是本地访问的,即http://localhost/index.html,而cookie的域是120.111.111.123的,因此不行了。因而乎继续改服务器
#path index.html <html> <head> <meta charset="utf8"> </head> <body> <input type="button" onclick="request()" value="请求"> </body> <script type="text/javascript" src="./ext-all.js"></script> <script type="text/javascript"> function request(){ Ext.Ajax.request({ url: 'http://120.111.111.123/setcookie.php', method: 'POST', params: { 'text': 'hello world' }, withCredentials: true, # 加了这个 success: function(transport){ // do something }, failure: function(transport){ alert("Error: " - transport.responseText); } }); } </script> </html>
继续访问,报错
XMLHttpRequest cannot load http://120.111.111.123/setcookie.php. Response to preflight request doesn't pass access control check: A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true. Origin 'null' is therefore not allowed access. The credentials mode of an XMLHttpRequest is controlled by the withCredentials attribute.
如今这个错误产生的缘由就是
1.由于加入了withCredentials以后,Access-Control-Allow-Origin就不能用“*”了,既然不容许访问这个源,那我就让你发个报文头让你容许访问呗!
<?php #path setcookie.php session_start(); // 是否存在请求源 if(isset($_SERVER["HTTP_ORIGIN"])) { header('Access-Control-Allow-Origin:'.$_SERVER["HTTP_ORIGIN"]); } header('Access-Control-Allow-Methods:OPTIONS, GET, POST'); header('Access-Control-Allow-Headers:x-requested-with'); header('Access-Control-Max-Age:86400'); // 功能... // ... ?>
好了,上传完代码,继续测试。发送请求以后,又报错了(这错中错,一个个坑搞的你们都看得不耐烦了吧,我保证,这是最后一个报错了)
XMLHttpRequest cannot load http://120.111.111.123/setcookie.php. Response to preflight request doesn't pass access control check: Credentials flag is 'true', but the 'Access-Control-Allow-Credentials' header is ''. It must be 'true' to allow credentials. Origin 'null' is therefore not allowed access.
大概的意思就是说我给你发了withCredentials报文头,可是你服务器没有跟我说容许我带这个报文头,那么解决方法就是加上容许发这个报文头的报文头
# path setcookie.php
<?php session_start(); // 是否存在请求源 if(isset($_SERVER["HTTP_ORIGIN"])) { header('Access-Control-Allow-Origin:'.$_SERVER["HTTP_ORIGIN"]); } header('Access-Control-Allow-Origin:null'); header('Access-Control-Allow-Methods:OPTIONS, GET, POST'); header('Access-Control-Allow-Headers:x-requested-with'); header('Access-Control-Max-Age:86400'); header('Access-Control-Allow-Credentials:true'); // 功能... // ... ?>
接下来进行最终的测试,biu~成功了,终于成功了!!!(0.0本身嗨起来了)
接下来总结一下,之因此跨域会引发那么多问题,都是由于耿直的客户端,发什么类型的请求都要服务器容许,并且要明文容许,容许的内容包括以下
1.跨域容许
解决方法:服务器发送容许客户端发送源的报文头
header('Access-Control-Allow-Origin:'.$_SERVER["HTTP_ORIGIN"]);
2.客户端没法携带跨域cookie
这个时候就能够在extjs中加入withCredentials
Ext.Ajax.request({ url: 'http://120.111.111.123/setcookie.php', method: 'POST', params: { 'text': 'hello world' }, withCredentials: true, success: function(transport){ // do something }, failure: function(transport){ alert("Error: " - transport.responseText); } });
3.由于加了withCredentials报文头,但是客户端不知道服务器允不容许报的错(耿直的客户端)
这个时候就在服务器发送Access-Control-Allow-Credentials
header('Access-Control-Allow-Credentials:true');
4.因为客户端不知道服务端是否容许POST请求而报的错
这个时候要在服务器端加入
header('Access-Control-Allow-Methods:OPTIONS, GET, POST'); header('Access-Control-Allow-Headers:x-requested-with'); header('Access-Control-Max-Age:86400');
以上汇总起来就是
header('Access-Control-Allow-Methods:OPTIONS, GET, POST'); header('Access-Control-Allow-Headers:x-requested-with'); header('Access-Control-Max-Age:86400'); header('Access-Control-Allow-Origin:'.$_SERVER['HTTP_ORIGIN']); header('Access-Control-Allow-Credentials:true'); header('Access-Control-Allow-Methods:GET, POST, PUT, DELETE, OPTIONS'); header('Access-Control-Allow-Headers:x-requested-with,content-type'); header('Access-Control-Allow-Headers:Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With');