session是使用在服务端的,跟客户端的页面字符集怎么会扯上关系呢?这多少会让人有些困惑。不过若从session的工作原理来理解的话,就容易明白了。关于session的工作原理,请参考http://wen5566.blog.51cto.com/1040211/563107。
假设用户从页面A输入用户名和密码,然后提交到页面B对用户名和密码进行验证,如果通过验证,则把用户名存入session中,然后再重定向到页面C。页面C需要判断用户是否已经登录,如果没有,则拒绝访问。在我开发的一个网站中,页面B的代码如下:
print "<meta http-equiv='Content-Type' content='text/html; charset=gb2312'>";
......
session_start();
$_SESSION['username']=$username;
print "<script>window.location='course.php'</script>";
为什么有print "<meta http-equiv='Content-Type' content='text/html; charset=gb2312'>";这句呢,主要是为了避免给国外的用户访问时会出现乱码。页面C检测用户是否登录的代码如下:
session_start();
if($_SESSION['username']=="")
{
print "<script><meta http-equiv='Content-Type' content='text/html; charset=gb2312'>;alert('Please log in first, thank you!');window.location='../index.php'</script>";
exit;
}
这样用户每次都得登录两次才能登录成功,是什么问题会造成这种情况呢?排查了一个上午,终于发现了问题所在,就是<meta http-equiv='Content-Type' content='text/html; charset=gb2312'>这个搞的鬼,造成页面B保存session和页面C读取session不一致,最根本的原因就是<meta http-equiv='Content-Type' content='text/html; charset=gb2312'>会对保存在客户端cookie中的PHPSESSID编码产生影响。解决方案就是每个页面写入读取session前客户端页面编码也要一致。对于我这边,只要把页面C的代码调整为如下即可:
print "<meta http-equiv='Content-Type' content='text/html; charset=gb2312'>";
session_start();
if($_SESSION['username']=="")
{
print "<script>alert('Please log in first, thank you!');window.location='../index.php'</script>";
exit;
}
问题特殊,google了很久,没找到同类的问题和解决方案,故撰此文,以此志之。