跨域php,如何处理前端js跨域问题-php

前端程序使用extjs写,在本地测试,发送请求到服务器时,发现存在跨域的问题,cookie也没有set成功,于是乎在这里整理一下解决过程

由于篇幅较长,不想看解决过程的可以翻到最后看总结

1.跨域允许

2.客户端无法携带跨域cookie

3.因为加了withCredentials报文头,可是客户端不知道服务器允不允许报的错

4.由于客户端不知道服务端是否允许POST请求而报的错

假设我的服务器IP是120.111.111.123

# 本地的html

# index.html

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);

}

});

}

#服务器的php文件

#path setcookie.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:*');允许所有源

session_start();

header('Access-Control-Allow-Origin:*');

// 功能...

// ...

然后又报错

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请求),验证成功后才会发送真正的请求

#用谷歌的开发者工具抓的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'); // 允许访问的有效期

// 功能...

// ...

继续测试我们的新功能,成功的解决了跨域问题

4a1ea2e6016d7c4acf8aa891c0b63bbe.png

but,cookie没有“设置成功”。而之所以没有“设置成功”,是因为cookie存在本地,但是每个cookie都有一个domain,当你本地的cookie中存在你当前访问的域时,才会被带过去,而我的index.html文件是本地访问的,即http://localhost/index.html,而cookie的域是120.111.111.123的,所以不行了。于是乎继续改

#path index.html

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);

}

});

}

继续访问,报错

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就不能用“*”了,既然不允许访问这个源,那我就让你发个报文头让你允许访问呗!

#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

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自己嗨起来了)

0d47139ba5d6f770935132e89d0a2c61.png

接下来总结一下,之所以跨域会引起那么多问题,都是因为耿直的客户端,发什么类型的请求都要服务器允许,而且要明文允许,允许的内容包括如下

1.跨域允许

解决方法:服务器发送允许客户端发送源的报文头

header('Access-Control-Allow-Origin:'.$_SERVER["HTTP_ORIGIN"]);

95ba50af6e4b74bea14ee73a0d8ef37a.png

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');

代码已经放到github了,有啥问题欢迎大家指出

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值