标签/Tag为[cookie]的文章

Movable Type 和 JS 删除 cookie 操作的弯路 ,

This is a sitelog of Easun.org.

话说: Movable Type 用户登录后退出貌似是http://easun.org/path_to_mt/mt.cp?__mode=logout&...

然后 302 回到当前页面。

这个过程究竟是干什么呢? 首先清理掉了 Session,这个是必须服务器支持的。

那么问题来了, 能不能不 302 ,直接我用 ajax 访问 上面的那个链接 OK ? 测试了一下。貌似 js 清除的 cookie 的值 mt_blog_user 为只是前台使用的。 后台使用还有 "mt_commenter","commenter_name","commenter_id" 这三个 cookie。 而 302 回原来界面的时候会清除这些 cookie.

知道了答案,于是开始修改,逻辑很清楚,ajax 访问上面的链接,清除服务器Session,然后自己写JS,清除这些 cookie,不就和原来逻辑一样了吗? 这样,点"退出"的时候页面不会跳转,会友好的多。

修改如下:

  1. 增加 clear_login_cookie 函数:如下

    javascriptfunction clear_login_cookie() {
    var name_array = ["mt_commenter","commenter_name","commenter_id"];
    var i = name_array.length;
    while (i--) {
    var name= name_array[i];
    mtDeleteCookie(name,mtCookiePath, mtCookieDomain,
    location.protocol == 'https:');
    }
    }
    ```
    
  2. 修改 mtSignOut 函数。
    定位 location.href = url; 修改为:

    code//location.href = url;
    clear_login_cookie();
    $.get(url, {ajax:'1'});
    mtFireEvent('usersignin');
    

    以为万事大吉,结果,运行之,发现虽然显示退出了, 但是mt_commenter","commenter_name","commenter_id 三个 cookie 并没有清理掉???

多处 Debug 无果, 最后又回归到了原来的模式,仔细研究了一下直接访问 302cookie 设定:

mt_commenter=; path=/; expires=Fri, 25-Sep-2015 02:02:10 GMT

commenter_name=; path=/; expires=Fri, 25-Sep-2015 02:02:10 GMT

commenter_id=; path=/; expires=Fri, 25-Sep-2015 02:02:10 GMT

呃,貌似根本没有 CookieDomain 设定。。。。 根本原因在于:

JS如果要删除(重新设置)某个 cookie ,必须知道原来设置的 pathdomain,不然会认为是完全不同的两个 cookie , 而悲催的事情是 js 无法获知原来设置的 cookie 的 pathdomain的。

原因知道了,只好硬编码了。幸好 mtCookiePath 定义的本身就是 /,回到 function clear_login_cookie(),重写如下:

code <!--lang:javascript-->
function clear_login_cookie() {
var name_array = ["mt_commenter","commenter_name","commenter_id"];
var i = name_array.length;
while (i--) {
var name= name_array[i];
mtDeleteCookie(name,mtCookiePath);
}
}

再次测试,一切 OK 。 但是弯路浪费了我 N 长时间。 记下来供同好者鉴。

吐槽一下: 为什么 Movable Type 设定这些 cookie 要和 公开的 cookie (mt_blog_user) 设定不同的 pathdomain 呢? 费解。

--EOF--

[SiteLog]JQ AJAX 跨子域Post再总结 ,

为了配合 CDN 前台。 后台的域名改成了 mt.easun.org/cgi-bin。 之所以启用子域而不是独立域名,是因为同域不同子域间可以天然共享 cookie ,而MT的POST必须带有 cookie ,不然登录信息验证不过。

测试一下正常的POST,没有任何问题。cookie 由于 CookieDomain 为 .easun.org ,所以cookie信息正常传递给了 mt.easun.org 后台。

但是接下来用 JQ $.post 进行 AJAX POST 的时候,就出现跨域问题了。 如果是Get,很简单,可以参考我上篇( [JQ+Perl]JQ AJAX跨域请求HTML/JS页面内容总结 )解决之。 POST 就必须设置跨域请求了。

不想回归 iframe 。幸好服务器部分配置可以自己控制。在后台脚本目录建立 .htaccess,内容如下:

code<IfModule mod_headers.c>
Header set Access-Control-Allow-Credentials: true
Header set Access-Control-Allow-Origin "http://easun.org"
</IfModule>

这下应该可以 $.post 了吧?

但是结果依然很悲哀,这次 POST 成功, 但是 JQ 并不传递 Cookie。导致身份认证出错。 Google之。发现跨域(包括子域), 如果要传递Cookie, JQ AJAX 还需要手动发送认证凭证,设置 withCredentials ,这样才会传递 Cookie.

根据这些信息。 重写 $.post$.ajax 模式,代码如下:

code$.ajax({
type: 'POST',
cache:false,
url: url,
data: $("#comments-form").serialize(),
success: function(data){
if (f.preview.value =='1' ) { EasunisPreReturn(data);}
else {EasunisPostReturn(JSON.parse(data));}
},
xhrFields: { withCredentials: true },
});
return false;

调试之,一切OK。

参考资料:

1.【前端笔记】使用ajax跨域withCredentials的作用

后记:

对于IE8,9 来说。JQ AJAX 跨子域Post 即使设置了上述也会失败。原因很奇葩,跨域提交需要使用 XDomainRequest 对象。

幸好有 JQ 插件 jQuery-ajaxTransport-XDomainRequest 可以解决。 在 $.ajax 前引入:

code<!--[if lte IE 9]>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery-ajaxtransport-xdomainrequest/1.0.3/jquery.xdomainrequest.min.js"></script>
<![endif]-->

同时,为了兼容出错信息,当$.ajax 失败的时候,设定正常方式POST。虽然这样界面乱了,但是保证功能正常。

codeerror: function(){ f.submit(); }

--EOF--

[Perl]一段cookie操作的封装代码

顺手写下,防止忘掉。
草稿,估计定稿不会是这个 :D
原因: 网站下同时存在多个相同的程序的副本,但是并不想 cookie 相互影响;
代码如下

###---- cookie By EasunLee 2012-03-11--------###
sub get_cookie_path
{
if ($esB::INFO->{'COOKIE_USED'} eq 1) { $esB::INFO->{'cookiepath'} ='';}
else {
my $boardurltemp = $esB::INFO->{'BBS_URL'};
$boardurltemp =~ s/http\:\/\/(\S+?)\/(.*)/\/$2/;
$esB::INFO->{'cookiepath'} = $boardurltemp;
$esB::INFO->{'cookiepath'} =~ s/\/$//;
}
$esB::INFO->{'cookiepath'} ;
}
# 设定cookie
sub set_cookie_str
{
my ($name,$value,$expires) =@_;
&get_cookie_path() unless ( defined ( $esB::INFO->{'cookiepath'} ) ) ;
my $prefix = $esB::INFO->{'cookie_prefix'} ;
$esB::CGI->cookie(-name => $prefix.$name, -value => $value, -path => $esB::INFO->{'cookiepath'}.'/', -expires => $expires);
}
# 读取cookie
sub get_cookie_str
{
my $name =shift;
&get_cookie_path() unless ( defined ( $esB::INFO->{'cookiepath'} ) ) ;
my $prefix = $esB::INFO->{'cookie_prefix'} ;
$esB::CGI->cookie (-name => $prefix.$name) ;#, -path => $esB::INFO->{'cookiepath'}.'/');
}
#### End cookie subs