基於thinkphp的ajax跨域解決方案

週末在家仔細研究了一下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;有效)

相關文章
相關標籤/搜索