|
本帖最后由 elftail 于 2011-12-16 00:04 编辑
在这里把我遇到的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(); ?>
给个实例代码? (我们都喜欢具体的实例代码不是吗? {:soso_e112:}) 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!
还有如果有其他在写ajax时需要注意的地方或者经验,欢迎一起分享,不胜感激.
----------------------------------------------------------------------------------------
第一次时发问题的帖子,没删,保留.
经过firphp 调试,发现数据送到服务器,但是firebug上提示
http://localhost:8888/ci/index.php/test/ajax 200 OK 的错误提示,并执行error函数
对ajax 刚接触,不知道哪里出错了,请大家帮忙看一下,谢谢
这个问题已经解决,要把localhost 改成 127.0.0.1 不过不知道为什么要这样
回答:这个是javascript的安全限制,不能跨域。(感谢 huboo82的回答)
-----------------------------------------------------------------------------------------
|
|