PSGI specification将HTTP响应定义为由三部分组成,第三部分可以是数组引用,也可以是文件句柄。文件句柄可能是:
一个IO :: Handle-like对象或内置文件句柄。
规范继续说:
服务器可以使用fileno和Scalar :: Util :: reftype检查主体是否是真正的文件句柄,如果它是具有文件描述符的真实文件句柄,它可以使用sendfile(2)等技术优化文件服务。 / BLOCKQUOTE>现在我使用
plackup
(Plack版本0.9978)拼凑了一个命令行示例,看来检查正文是否是真正的文件句柄会导致致命错误:
Can't locate object method "FILENO" via package "IO::Scalar" at /usr/lib/perl5/5.10/i686-cygwin/IO/Handle.pm line 390
这是命令行示例:
plackup -MData::Dumper -MIO::Scalar -e \ 'sub { $env=shift; return [200, [], IO::Scalar->new(\Dumper $env) ] }'
当然我可以不使用文件句柄:
plackup --port 9999 -MData::Dumper -e \ 'sub { $env=shift; return [200, [], [Dumper $env] ] }'
但我对什么有效,什么不有意义感兴趣。因此,当在句柄上调用
FILENO
时,Plack不应该更加谨慎,这样它就不会遇到异常吗?并添加另一个:
plackup --port 9999 -MData::Dumper -e \ 'sub{$env=shift; $s=Dumper $env; open $fh,q(<),\$s or die; return [200,[],$fh ]}'
看起来像文件句柄不被识别。错误消息是:
body should be an array ref or filehandle at /usr/lib/perl5/site_perl/5.10/Plack/Middleware/StackTrace.pm line 35
更新
正如他在回答中所述,以下内容将起作用(至少在Cygwin的5.10.1上):
plackup -p 9999 -MData::Dumper -MIO::String -e \ 'sub { return [200, [], IO::String->new(\Dumper shift) ] }'
但显然,从失败的例子中可以看出某个地方存在问题,一旦我弄清楚它实际上是什么,就会报告。
答案 0 :(得分:9)
这些不是错误 - 实际上更容易将其称为Plack中的错误并修复以将其作为有效响应处理。但这会让事情变得更糟,因为现在Plack处理的事情并没有(明确地)定义为PSGI规范中的正确响应。 (PSGI!= Plack,同样是HTTP!= Apache)
PSGI规范的要点是它是Web服务器和应用程序之间的通用接口。如果服务器/应用程序需要添加额外的2-3行代码以符合规范,那么这是一个很好的折衷方案。在每个N个应用程序和M个服务器中拥有2-3行代码要好得多,而不是在应用程序中使用N * 2-3行额外代码来处理服务器中的极端情况,反之亦然。
规范定义响应主体应该是“内置文件句柄”或“实现getline的IO :: Handle-like对象”。在Plack中处理与此类似的工作很容易,但我们不应盲目地这样做 - 请记住,Plack并不是唯一的PSGI实现。 Lint中间件警告您关于该不兼容性是正确的事情。
那说:
a)IO :: Scalar是一个实现getline()方法的对象,因此应该被接受。不幸的是,正如其他人所指出的那样,Lint因为模块的错误而死在它身上。使用猴子修补可以很容易地解决它,并且修复Plack :: Util :: is_real_fh以便在 - &gt; fileno调用中捕获错误也很容易,但是,如果它是正确的事情要做。
b)PerlIO内存文件句柄是一件棘手的事情。规范只说“内置文件句柄”,内存文件句柄也可以作为内置的东西。实际上,如果您禁用Lint中间件(例如,使用-E production
选项进行plackup),文件句柄就可以正常工作。但同样,Lint中间件会给你一条消息,因为它不能保证在其他地方工作。
最后但并非最不重要的是,这应该在FAQ中解决。随意在psgi-specs存储库中打开一个案例。
答案 1 :(得分:8)
这似乎是普拉克的一个错误。它试图通过fileno来确定它是否有真正的文件句柄,如果不是,它只接受getline
方法的对象。如果没有FILENO
定义的绑定文件句柄(有效,如果不礼貌)和内存文件句柄中没有有效的fileno也不是它们是受祝福的对象,则会错过这两个文件句柄。您可以在Plack::Middleware::Lint->validate_res
和Plack::Util->is_real_fh
中的逻辑中看到它。
同时,您可以通过定义IO :: Scalar :: FILENO来返回undef来解决IO :: Scalar中的问题。
sub IO::Scalar::FILENO { return }
这将改进IO :: Scalar,但它在六年内没有更新,所以我不会屏住呼吸。
要允许在内存文件句柄中,您可以通过祝福文件句柄来欺骗Plack。打开它并将其交给之间的某个时间,请执行以下操作:
bless $fh, "IO::Handle";
这是无害的,因为任何文件句柄都会响应IO :: Handle方法。但也请把它报告为一个错误。
答案 2 :(得分:0)
看起来像IO :: Scalar中的一个错误。报告它,并且insteaad使用IO :: String或5.8中添加的内置文件支持。