关于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!

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。