週末在家仔細研究了一下ajax跨域的問題,雖然能夠用jsonp但jsonp只能用於GET請求,因此仍是深刻了一下。javascript
CORS的具體內容你們可網上搜一下,這裏主要是設置一個名爲「Access-Control-Expose-Headers」的報頭對響應報頭進行受權。PHP中使用header("Access-Control-Allow-Origin:*");就能夠了。php
thinkphp中 控制器返回以前加一行header("Access-Control-Allow-Origin:*");也能成功,可是若是每一個控制器函數都寫這麼一句就太費事了。因此建立了一個AjaxController類繼承Controller類,並在構造函數中添加了html
class AjaxController extends Controller {
public function __construct(){
parent::__construct();//調用父類的方法,由於這裏重寫了父類的方法
//用於解決前臺ajax跨域請求
header("Access-Control-Allow-Origin:*");
//header("Access-Control-Allow-Origin:http://111.com");
}
}
其餘控制器所有繼承此類java
class IndexController extends AjaxController {
測試成功。但又發現另外一個問題jquery
thinkphp文檔裏提到的success和error方法會自動判斷當前請求是否屬於Ajax請求,若是屬於Ajax請求則會調用ajaxReturn方法返回信息。 ajax方式下面,success和error方法會封裝下面的數據返回:web
通過一翻排查發現success並無以ajax方式返回。這裏有兩個解決方法,一是指定success的第三個參數爲true(error同理)。ajax
但這樣就失去了靈活性,本着一挖到底的原則最後找到了\ThinkPHP\Library\Think\Controller.class.php中的thinkphp
private function dispatchJump($message,$status=1,$jumpUrl='',$ajax=false) {
if(true === $ajax || IS_AJAX )
這裏用於判斷是否爲ajax提交過來的。IS_AJAX在\ThinkPHP\Library\Think\App.class.php中,內容爲json
define('IS_AJAX', ((isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') || !empty($_POST[C('VAR_AJAX_SUBMIT')]) || !empty($_GET[C('VAR_AJAX_SUBMIT')])) ? true : false);
看來IS_AJAX並不能很好的反映是否爲ajax提交。因此在App.class.php又增長了IS_AJAX2的定義跨域
switch ($_SERVER['HTTP_ACCEPT']){//定義常量IS_AJAX2 用於判斷ajax跨域提交
case 'application/json, text/javascript, */*':
// JSON 格式
define('IS_AJAX2',true);
break;
case 'text/javascript, application/javascript, */*':
// javascript 或 JSONP 格式
define('IS_AJAX2',true);
break;
case 'text/html, */*':
// HTML 格式
break;
case 'application/xml, text/xml, */*':
// XML 格式
break;
}
並修改Controller.class.php中dispatchJump函數
private function dispatchJump($message,$status=1,$jumpUrl='',$ajax=false) {
if(true === $ajax || IS_AJAX ||IS_AJAX2) {//IS_AJAX2 用於判斷ajax跨域提交
這樣問題就完全解決了,但由於改動了框架函數,對於之後升級帶了不便,不知道有沒有其餘更好的方案。
還有另外一個須要修改的地方就是Controller.class.php中的ajaxReturn函數也要增長header("Access-Control-Allow-Origin:*"),否則的使用$this->ajaxreturn也不支持跨域
protected function ajaxReturn($data,$type='',$json_option=0) {
if(empty($type)) $type = C('DEFAULT_AJAX_RETURN');
switch (strtoupper($type)){
case 'JSON' :
// 返回JSON數據格式到客戶端 包含狀態信息
header('Content-Type:application/json; charset=utf-8');
header("Access-Control-Allow-Origin:*");//用於解決前臺ajax跨域請求 libo
exit(json_encode($data,$json_option));
case 'XML' :
// 返回xml格式數據
header('Content-Type:text/xml; charset=utf-8');
exit(xml_encode($data));
case 'JSONP':
// 返回JSON數據格式到客戶端 包含狀態信息
header('Content-Type:application/json; charset=utf-8');
header("Access-Control-Allow-Origin:*");//用於解決前臺ajax跨域請求 libo
$handler = isset($_GET[C('VAR_JSONP_HANDLER')]) ? $_GET[C('VAR_JSONP_HANDLER')] : C('DEFAULT_JSONP_HANDLER');
exit($handler.'('.json_encode($data,$json_option).');');
case 'EVAL' :
再說一下前臺的$.ajax須要注意的就是 在IE10中textStatus一直爲parsererror,致使結果一直爲error,測試發現是瀏覽器安全設置問題。而後在jquery官方找到了$.ajax的crossDomain: true,這個參數,但仍是沒效果。最後用了jQuery.support.cors = true;
jQuery.support.cors = true;//提供了這樣的方式來支持瀏覽器的跨站請求 IE10有效
$.ajax({
url: "http://xxxx/Home/index/ajaxlogin",
data: {"uid":$name,"upw":$pw},
timeout: 5000,
cache: false,
type: "POST",
dataType: "json",//若是返回類型與dataType不一樣,會使textStatus爲parsererror而致使執行error函數
crossDomain: true,//Jquery1.5以後,提供了這樣的方式來支持瀏覽器的跨站請求。(經測試IE10及如下無效,但在ajax請求前設置jQuery.support.cors = true;有效)