5

我有一些 Perl CGI 代码,我试图在 SourceForge 帐户的项目 Web 空间中运行。该代码能够在与 IE 对话时很好地设置浏览器 cookie,但在与 Firefox 对话时未设置 cookie。当我在“localhost”上使用 Apache 进行测试时,两个浏览器都可以正常工作。Firefox 只能在远程 SourceForge URL 上进行处理。

搜索出现了几十个几乎重复的问题,但通常人们遇到的问题完全相反!(Firefox 很好,IE 有问题)

这是我调用来设置 cookie 的实用程序子:

sub setCookie {
    my $name = shift;
    my $value = shift;
    my $expires = shift;
    my $path = shift;
    my $domain = shift;
    if( !defined( $expires ) ) {
        $expires = '+4h';
    }
    if( !defined( $path ) ) {
        $path = '/';
    }
    if( !defined( $domain ) ) {
        $domain = 'steveperkins.sourceforge.net';
    }
    my $cookie = CGI::cookie(
        -name    => $name,
        -value   => $value,
        -domain   => $domain,
        -expies => $expires,
        -path    => $path
    );
    $r->header_out('Set-cookie' => $cookie);
}

有任何想法吗?我的第一个想法是某种子域问题,因为我的 SourceForge 项目 URL 中有一个子域,而“localhost”没有。我已经尝试将 cookie 域设置为我的特定子域,或者只是基本的“sourceforge.net”。无论哪种方式,它似乎都没有什么不同。

更新: 下面的评论中有人询问了 HTTP 响应标头。我使用网络流量分析工具 Wireshark 来监控 IE 和 Firefox 的请求和响应标头,它们的外观如下:

IE(作品)

要求

GET http://myproject.sourceforge.net/cgi-bin/myscript.cgi?page=user&userID=1 HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-ms-application, application/vnd.ms-xpsdocument, application/xaml+xml, application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-shockwave-flash, */*
Referer: http://myproject.sourceforge.net/cgi-bin/myscript.cgi
Accept-Language: en-us
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.5.30729; InfoPath.1; .NET CLR 3.0.30618)
Proxy-Connection: Keep-Alive
Host: myproject.sourceforge.net
Authorization: Basic [password omitted]

回复

HTTP/1.1 200 OK
Server: nginx/0.7.63
Date: Tue, 26 Oct 2010 18:23:49 GMT
Content-Type: text/html; charset=ISO-8859-1
Expires: Thu, 28 Oct 2010 18:23:49 GMT
Cache-Control: max-age=172800, proxy-revalidate
Transfer-Encoding: chunked
Proxy-Connection: Keep-Alive
Connection: Keep-Alive
Content-Encoding: gzip
Set-Cookie: USER=1; domain=myproject.sourceforge.net; path=/

火狐(不工作)

要求

GET http://myproject.sourceforge.net/cgi-bin/myscript.cgi HTTP/1.1
Host: myproject.sourceforge.net
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.11) Gecko/20101012 Firefox/3.6.11
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Proxy-Connection: keep-alive
Cookie: __utma=191645736.1501259260.1287701281.1288028150.1288100562.10; __utmz=191645736.1288101011.10.10.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=sourceforge%20project%20web%20space%20basic%20auth; _jsuid=4215309712123065236
Authorization: Basic [password omitted]

回复

HTTP/1.1 200 OK
Server: nginx/0.7.63
Date: Tue, 26 Oct 2010 18:17:58 GMT
Content-Type: text/html; charset=ISO-8859-1
Expires: Thu, 28 Oct 2010 18:17:58 GMT
Cache-Control: max-age=172800, proxy-revalidate
Transfer-Encoding: chunked
Proxy-Connection: Keep-Alive
Connection: Keep-Alive
Content-Encoding: gzip
Age: 0
4

2 回答 2

5

我会说你在设置到期时有一个错误

if( !defined( $path ) ) {
    $expires = '/';
}

应该

if( !defined( $path ) ) {
    $path = '/';
}

更新:根据您在上面使用wireshark提供的信息,我将检查是否在Firefox进入时实际调用了setCookie。(顺便说一句,两个URL都不同,这可能表明您的代码中的逻辑跳过了setCookie调用基于网址)。还尝试在两个浏览器中使用相同的 URL,看看会发生什么。

于 2010-10-26T15:25:17.620 回答
2

啊!事实证明,问题是在“localhost”上运行时只有一个 cookie 在运行,但在 SourceForge 的服务器上托管时有多个 cookie 在运行。

如果您查看上述问题中剪切并粘贴的 Firefox 请求标头,您会注意到有几个 cookie 名称-值对……每对用分号分隔。 我的代码没有解决这个问题,所以它看到的只是一个巨大的格式错误的 cookie。

我仍然不是 100% 确定它为什么在 IE 中部分工作,我可能会在未来重新审视这个,看看是否可以学到更多。但这现在基本上是一个有争议的问题。我将代码更改为以分号拆分,然后以等号拆分,我现在处理 cookie 就好了。

感谢大家的见解和建议!Pierre-Luc,出于对下面所有评论的感谢,我确实给了你的答案一个赞成票。

    sub getCookie {
    my $cookieName = shift;
    my %headers = $r->headers_in;
    my @keys = keys( %headers );
    foreach my $name ( @keys ) {
        if( $name eq 'Cookie') {
        my @semicolontokens = split( ';', $headers{$name} );
        foreach my $splitname ( @semicolontokens ) {
           $splitname =~ s/^\s+//;
           $splitname =~ s/\s+$//;
           my @pair = split( '=', $splitname );
               if( $pair[0] eq $cookieName ) {
               return $pair[1];
               }
           }
       }
   }
于 2010-10-27T04:31:59.997 回答