關於ajax的問題(整理回答,發佈正確的代碼,csrf)

在這裏把我遇到的ajax問題和你們的回答整理總結一下, 剛學CI,  可能有錯誤 ,但願指正。

若是你有如下問題,可能會獲得幫助:

1. 跨域訪問錯誤
2. csrf保護開啓後ajax出現錯誤
3. gZip開啓後出現ajax錯誤

測試環境
Ubuntu: firefox, chrome
windows XP: IE, 360瀏覽器的IE8

1. 跨域訪問
(下面的問題常常出如今你載入ajax視圖和處理ajax請求是同一個控制器時,是特殊狀況,

但由於這是我遇到的第一個問題, 並且折磨了我好久,因此仍是寫出來了,但願別人能避開這個錯誤)

(1)當ajax的請求地址控制器處理程序的地址不一致時會出現錯誤。

如 ajax在域名' www.444.com '的視圖裏, 請求的是 ' www.333.com /ci/index.php/test/ajax' ,
則會出現跨域訪問錯誤,個人提示是  301 Moved Permanently

(2) localhost和127.0.0.1是不一樣的域

解釋:
這個是javascript的安全限制,不能跨域。
(感謝 huboo82的回答)

localhost也叫local ,正確的解釋是:本地服務器 
127.0.0.1在windows等系統的正確解釋是:本機地址(本機服務器) 
localhot(local)是不經網卡傳輸 !這點很重要,它不受網絡防火牆和網卡相關的的限制。 
127.0.0.1是經過網卡傳輸,依賴網卡,並受到網絡防火牆和網卡相關的限制。
(感謝credochen的回答)

(3) www.ddd.com 和 ddd.com 是不一樣的域。
解釋:
若是ajax請求的地址和控制器的地址裏www不一致,則出錯.
(不知道是否是我電腦的錯誤,我在視圖 a.php請求的是 "www.ddd.com/ci/index.php/test/ajax", 若是我在url用 「ddd.com/ci/index.php/test」控制器載入視圖,而後用同一個控制器處理ajax請求就出錯,加上www就沒有錯。)

(4) ajax請求若是是完整路徑,則加上"http://" ,否則Codeigniter會自動在你的地址前面
加上默認路徑變成  http://www.ddd.com/ci/index.php/test/ www.ddd.com/ci/index.php , 
而這可能不是你的本意

個人解決方法: (不是很好,可是有用)
1)載入視圖的和處理ajax請求的分紅不一樣的控制器, 這樣ajax的請求就不用擔憂與調用的,
控制器地址不同.

2)若是你把調用ajax視圖和處理請求的都放到同一個控制器文件裏的話.

PHP 複製代碼
 
         var body  = $ ( "body" ) ;
         var baseUrl  = body .context .baseURI ;
 
複製代碼


context.baseURI  會獲得載入本視圖的地址,這樣就能和服務其上的地址一致,避免一些錯誤,
但這個沒有把全部狀況考慮進去,你須要本身對這個地址設定一些條件檢查。

2.csrf 保護的問題
config裏設置 $config['csrf_protection'] = TRUE;  會對post進行 csrf保護,
他會對用戶提交的數據進行檢查,能夠提升安全,建議開啓。固然會引起一些問題。

(1)簡單的說就是你提交的數據中若是沒有特定的值給控制器,就回出錯。
-----------------------------------------------------------------
詳細的解釋: ( 這裏能夠看原帖
感謝c361239752的回答
最近研究CI源碼,正好看到CSRF保護,原理是這樣的:在config中設置了開始CSRF保護,用form生成表單會生成hidden的一段HASH值,這段HASH會被寫入到cookies中源碼以下:
setcookie($this->_csrf_cookie_name, $this->_csrf_hash, $expire, config_item('cookie_path'), config_item('cookie_domain'), $secure_cookie);
其中cookie_domain做用域是config中設定的,提交POST後會判斷post過來的token和cookies中的token是否存在,再判斷這兩個值是否相等,不然顯示錯誤頁面,判斷完後當即unset($_POST[$this->_csrf_token_name]);unset($_COOKIE[$this->_csrf_cookie_name]);以免污染$_POST數據
-------------------------------------------------------------------

不要被這個解釋給嚇倒了,其實你要作的只是把一個變量加到你的ajax的提交的數據裏,
這個變量定義在你的 $config['csrf_token_name'] = 'csrf_test_name';
這裏主要提交的數據是 csrf_test_name的值,Codeigniter會自動添加到Cookie裏.

那如何獲得哪一個變量和值? 
這個會返回你要的值
<?php echo $this->security->get_csrf_hash(); ?> 

這個會返回你要傳遞的變量名(就是你設置在 $config['csrf_token_name']
<?php echo $this->security->get_csrf_token_name(); ?>

給個實例代碼? (咱們都喜歡具體的實例代碼不是嗎?  )
PHP 複製代碼
 
            $.ajax({
                type: " OST",
                // 這裏是你的請求地址
                url: "www.ddd.com/ci/index.php/test/ajax",
                data: "name="+cv+'&'+" <?php  echo  $this -> security -> get_csrf_token_name ( ) ;  ?>"+'='+" <?php  echo  $this -> security -> get_csrf_hash ( ) ;  ?>",
                success: function(msg){
                    mydiv.html(msg).show();
                },   
                error: function() {
                   alert("ajax error")
                ;}
            });
 
 
複製代碼

(2) 表單提交時出錯

若是你開啓了csrf,而後直接用純 <from ..></form>格式提交表單就會出錯.緣由同上

解決方法
1)用Codeigniter的 form_open() 函數,codeigniter會自動把驗證代碼插入到視圖表單裏,而後隱藏並
跟你的數據一塊兒提交。(推薦)
2)用上面的方法得到數據,而後提交.

相關資料:
http://blog.hsin.tw/2011/codeigniter-csrf-protection-form-ajax/
這個博客文章的解決方法很好,惋惜代碼有錯誤,不過仍是值得參考(我就是從這裏獲得幫助,解決了問題)
http://codeigniter.com/forums/viewthread/163976/
在這裏我找到了解決方法的代碼.

3. gZip壓縮開啓
若是你設置了$config['compress_output'] = TRUE; 不能在任何控制器裏使用 echo
由於若是你在控制器用echo輸出的方法返回ajax數據,就回出現編碼錯誤

解決方法:
1. (推薦)
$data = "your ajax return data";
$this->output->set_output($data); (推薦) 
2. $this->load->view('data'); (會把視圖內容傳輸給客戶端)

最後讓咱們貼出激動人心的完整的美麗的強大的......實例代碼,用於參考
(我在Ubuntu的firefox和chrome,還有xp裏的IE裏測試過,不保證其餘瀏覽器裏也正確
我使用了jQuery, 請確保jQuery包含了進來,固然你也能夠改爲純js.)

視圖. ajax.php

HTML 複製代碼
 
<!DOCTYPE HTML>
<html lang="en">
<head>
     <script type="text/javascript"    src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
 
 
     <script type="text/javascript">
    $(document).ready(function() {
 
        var mydiv = $("#myDiv");
 
 
        function swapContent(cv) {
            // ajax請求時的等待圖片能夠寫在這裏
            mydiv.html(" ut animated .gif here").show();
 
            // 由於我調用這個視圖的和處理這個ajax的控制器是同一個,因此
            // 可能會出現跨域錯誤
            var u = "http://127.0.0.1/ci/index.php/test/ajax";
 
            $.ajax({
                type: " OST",
                url: u,
                data: "name="+cv+' &'+"<?php echo $this->security->get_csrf_token_name(); ?>"+'='+" <?php echo $this->security->get_csrf_hash(); ?>",
                success: function(msg){
                    mydiv.html(msg).show();
                },   
                error: function() {alert("ajax error");}
            });
        }
 
        $("#c1").click(function() {
            swapContent("d1");
        });
 
        $("#c2").click(function() {
            swapContent("d2");
        });
 
        $("#c3").click(function() {
            swapContent("d3");
        });
 
    });
     </script>
         <meta charset="UTF-8">
         <title></title>
</head>
<body>
     <a id ="c1" href="#" >Content1 </a>
     <a id = "c2" href="#" >Content2 </a>
     <a id = "c3" href="#" >Content3 </a>
     <div id="myDiv">My default content </div>
 
</body>
</html>
 
 
複製代碼



控制器 test.php



PHP 複製代碼
<?php 
 
class Test  extends CI_Controller  {
 
     public  function __construct ( ) {
        parent ::__construct ( ) ;
     }
      public  function index ( )
      {
         $this -> load -> view ( 'ajax' ) ;
      }
 
      function ajax ( )
      {
         $name  =  $this -> input -> post ( 'name' ) ;
 
         $this -> output -> set_output ( 'server get data: ' . $name ) ;
      }
}
 
 
複製代碼



(全文完)
:wq!
相關文章
相關標籤/搜索