Perl工具链峰会需要更多赞助商。如果您的公司取决于Perl,拜托支持这一非常重要的活动.

名称

PSGI-Perl Web服务器网关接口规范

摘要

本文档指定了web服务器和Perl web应用程序或框架之间的标准接口。此界面旨在提高web应用程序的可移植性,并减少web应用程序框架开发人员的重复工作。

请记住,PSGI并不是另一个web应用程序框架。PSGI是一个规范,用于将web服务器环境与web应用程序架构代码解耦。PSGI也不是web应用程序API。Web应用程序开发人员(最终用户)不会直接使用PSGI界面运行其Web应用程序,而是鼓励使用支持PSGI的框架。

术语

Web服务器

Web服务器接受web客户端发出的HTTP请求,如果配置为这样做,则将这些请求发送给web应用程序,并将HTTP响应返回给请求发起客户端。

PSGI服务器

A类PSGI服务器是一个Perl程序,为PSGI应用跑进去。

PSGI指定web应用程序的接口以及web应用程序用于Internet的主要目的PSGI服务器很可能是:网络服务器的一部分(如Apache mod_perl),连接到网络服务器(使用FastCGI、SCGI),由网络服务器调用(如普通的旧CGI),或者是独立的网络服务器本身,完全或部分用perl编写。

然而,不要求PSGI服务器成为web服务器或其一部分PSGI公司只定义服务器和应用程序之间的接口,而不是服务器和世界之间的接口。

A类PSGI服务器通常也称为PSGI应用程序容器因为它类似于Java Servlet容器,它是Java进程,为Java Servlet.

应用程序

Web应用程序接受HTTP请求并返回HTTP响应。

PSGI应用程序是符合PSGI接口的web应用程序,规定它们采用具有定义的输入和输出的代码引用形式。

为了简单起见,PSGI应用程序也被称为应用程序用于本文档的其余部分。

中间件

中间件是PSGI应用程序(代码引用)服务器.中间件看起来像一个应用当从服务器反过来,它可以调用其他应用。可以将其视为插件扩展PSGI应用程序。

框架开发人员

框架开发人员是web应用程序框架的作者。他们编写适配器(或引擎),接受PSGI输入,运行web应用程序,并向服务器.

Web应用程序开发人员

Web应用程序开发人员是在web应用程序框架之上编写代码的开发人员。这些开发人员不应该直接与PSGI打交道。

规范

应用程序

PSGI应用程序是一个Perl代码引用。它只接受一个参数,即环境,并返回包含三个值的数组引用。

我的$app=订阅{my$env=班次;返回['200',[“内容类型”=>“text/plain”],[“Hello World”]、#或IO::Handle-like对象];};

环境

环境必须是包含类似CGI的头的散列引用,如下所述。应用程序可以自由修改环境。环境必须包括这些键(采用自政治公众人物333,机架JSGI公司)除非它们通常是空的。

当一个环境键被描述为布尔值时,它的值必须符合Perl的布尔性概念。这意味着空字符串或显式0都是有效的false值。如果不存在布尔键,应用程序可能会将其视为假值。

所有CGI键(命名时不带句点)的值必须是标量字符串。

详见下文。

  • 请求_方法:HTTP请求方法,如“GET”或“POST”。这个不能为空字符串,因此总是必需的。

  • 脚本_名称:请求URL的初始部分路径,对应于应用程序。这会告诉应用程序其虚拟“位置”。如果应用程序对应于服务器的根URI,则这可能是一个空字符串。

    如果此键不为空,则必须以正斜杠开头(/).

  • 路径信息:请求URL的其余部分路径,指定应用程序中请求目标的虚拟“位置”。如果请求URL以应用程序根为目标,并且没有尾部斜杠,则这可能是一个空字符串。此值应为服务器解码的URI,以便与兼容副本请求3875.

    如果此键不为空,则必须以正斜杠开头(/).

  • 请求URI:未编码的原始请求URL行。它是出现在HTTP中的原始URI路径和查询部分获取/。。。HTTP/1.x协议行,不包含URI方案和主机名。

    不同于路径信息,此值不应该由服务器解码。如果应用程序选择使用此键而不是路径信息.

  • 查询_字符串:请求URL中位于?,如果有。此键可能为空,但必须永远在场,即使是空的。

  • 服务器名称,服务器端口:与结合时脚本_名称路径信息,这些键可用于完成URL。但是,请注意HTTP_主机如果存在,应优先使用服务器名称用于重建请求URL。服务器名称服务器端口 不能为空字符串,并且始终是必需的。

  • 服务器_ PROTOCOL:客户端用于发送请求的协议版本。通常这类似于“HTTP/1.0”或“HTTP/1”,应用程序可以使用它来确定如何处理任何HTTP请求头。

  • 内容_长度:内容的长度(以字节为单位),以整数表示。该密钥的存在与否应与请求中是否存在HTTP Content-Length标头相对应。

  • 内容_类型:请求的MIME类型,由客户端指定。此密钥的存在或不存在应与请求中是否存在HTTP Content-Type标头相对应。

  • HTTP协议_*密钥:这些密钥对应于客户端提供的HTTP请求头。这些键的存在与否应与请求中是否存在适当的HTTP标头相对应。

    将HTTP头字段名转换为大写,替换所有出现的连字符,即可获得密钥-带下划线_和预排HTTP协议_,如副本请求3875.

    如果有多个标题行使用同一密钥发送,服务器应将其视为在一行中发送,并将其与,,如RFC 2616号文件.

服务器应尝试提供尽可能多的其他CGI变量。然而,请注意,使用除上述变量以外的任何CGI变量的应用程序对于不支持相关扩展的web服务器来说都是不可移植的。

除上述密钥外,PSGI环境还必须包括这些特定于PSGI的密钥:

  • psgi.版本:表示此版本PSGI的数组引用[1,1]。第一个数字是主版本,第二个数字是次版本。

  • psgi.url方案:字符串httphttps(https),具体取决于请求URL。

  • psgi输入:输入流。详见下文。

  • psgi.错误:错误流。详见下文。

  • psgi.多线程:这是一个布尔值,如果应用程序可能被同一进程中的另一个线程同时调用,则该值必须为true,否则为false。

  • psgi.多进程:这是一个布尔值,如果另一个进程可以同时调用等效的应用程序对象,则该值必须为true,否则为false。

  • psgi.run_once(_O):如果服务器期望(但不保证!)应用程序在其包含进程的生命周期内只被调用一次,则为真的布尔值。通常,这只适用于基于CGI(或类似内容)的服务器。

  • psgi.非阻塞:如果服务器在非阻塞事件循环中调用应用程序,则为真的布尔值。

  • psgi.流媒体:如果服务器支持回调样式延迟响应和流式写入器对象,则为真的布尔值。

服务器或应用程序也可以在环境中存储自己的数据。这些键必须包含至少一个点,并且前缀应唯一。

这个psgi。前缀保留用于PSGI核心规范,并且psgix公司。前缀是为官方认可的扩展保留的。这些前缀不能被其他服务器或应用程序使用。请参见psgi-扩展获取正式批准的扩展列表。

环境不能包含名为HTTP_内容_类型HTTP_内容_长度.

什么之中的一个脚本_名称路径信息必须设置。什么时候?请求URI/,路径信息应该是/脚本_名称应为空。脚本_名称 不能/,但可能为空。

输入流

中的输入流psgi输入是一个IO::句柄-like对象,用于流式处理原始HTTP POST或PUT数据。如果是文件句柄,则必须以二进制模式打开。输入流必须响应阅读和MAY实施寻求.

Perl的内置文件句柄或IO::句柄基于的对象应该在PSGI服务器中作为-is工作。应用程序开发人员不应该检查流的类型或类。相反,他们应该直接打电话阅读在对象上。

应用程序开发人员不应该使用Perl的内置阅读或迭代器(<$fh>)从输入流中读取。相反,应用程序开发人员应该调用阅读作为一种方法($fh->读取)允许鸭子打字。

框架开发人员,如果他们知道输入流将与他们无法接触的任何上游代码中的内置read()一起使用,那么应该使用PerlIO或绑定句柄来解决这个问题。

输入流对象应提供阅读方法:

阅读
$input->read($buf,$len[,$offset]);

返回实际读取的字符数,文件末尾为0,如果出现错误,则返回undef。

它还可以实现可选的寻求方法。如果psgix.input.buffered(psgix.输入缓冲)环境为真,它必须实现寻求方法。

寻求
$input->seek($pos,$whence);

成功时返回1,否则返回0。

请参阅IO::句柄有关这些方法应该如何工作的详细信息,请参阅文档。

错误流

中的错误流psgi.错误是一个IO::句柄-like对象以打印错误。错误流必须实现打印方法。

与输入流一样,Perl的内置文件句柄或IO::句柄基于的对象应该在PSGI服务器中作为-is工作。应用程序开发人员不应该检查流的类型或类。相反,他们应该直接打电话打印在对象上。

打印
$errors->打印($error);

如果成功,则返回true。

回应

应用程序必须以三元素数组引用或延迟/流式响应的代码引用的形式返回响应。

响应数组引用由以下元素组成:

状态

HTTP状态代码。这必须是一个大于或等于100的整数,并且应该是HTTP状态代码,如中所述RFC 2616号文件.

标题

标头必须是数组引用(散列引用)。这意味着它必须包含偶数个元素。

标题不能包含名为状态,也没有带的任何键:或在其名称中添加换行符。不能包含以结尾的任何键-_.

所有键只能由字母、数字、,_-。所有按键必须以字母开头。标题的值必须是标量字符串并已定义。值字符串不能包含八进制037以下的字符,即chr(31)。

如果相同的密钥名称在数组ref中多次出现,则必须将这些标题行分别发送给客户端(例如,多个套餐-Cookie行)。

内容类型

必须有一个内容类型除非状态是1xx、204或304,在这种情况下不能是内容类型。

内容物-长度

那里不能成为内容物-长度标头,当状态是1xx、204或304。

如果状态不是1xx、204或304,并且没有内容物-长度标头,PSGI服务器可以通过查看Body来计算内容长度。然后,可以将此值附加到应用程序返回的标题列表中。

车身

响应正文必须作为数组引用或包含作为字节字符串的响应正文的句柄从应用程序返回。主体必须编码为适当的编码和不能包含宽字符(>255)。

  • 如果主体是数组引用,则应包含组成主体的行数组。

    my$body=[“Hello\n”,“World\n”];

    请注意,数组引用中的元素是不需要以换行结束。服务器应该将每个元素作为i写入客户端,并且不应该注意行是否以换行符结尾。

    具有单个值的数组引用有效。所以[$html]是有效的响应正文。

  • 主体可以是一个句柄,也可以是Perl内置的filehandle或IO::句柄-类似对象。

    打开我的$body,“</path/to/file”;打开我的$body,“<:via(SomePerlIO)”。。。;my$body=IO::File->new(“/path/to/File”);#实现getline()和close()的模拟类my$body=SomeClass->new();

    服务器不应该检查主体的类型或类别。相反,他们应该直接打电话给获取线路遍历主体并调用关闭完成后。

    服务器可以使用文件描述符标量::Util::reftype。如果主体是真实的文件句柄,服务器可以使用以下技术进行优化发送文件(2).

    主体对象也可以响应路径方法。此方法应返回服务器可访问的文件的路径。这允许服务器使用此信息而不是文件描述符编号来为文件提供服务。

    服务器应设置$/读取内容时缓冲区大小的特殊变量$主体使用获取线路方法。这是通过设置$/引用了一个整数($/ = \8192).

    如果主体文件句柄是Perl内置文件句柄IO::手柄对象,它们将尊重该值。类似地,提供相同API的对象也可能会尊重此特殊变量,但不需要这样做。

延迟响应和流体

PSGI接口允许应用程序和服务器提供回调类型的响应,而不是三元素数组引用。这允许延迟响应和流媒体主体(服务器推送)。

该接口应由PSGI服务器实现,并且psgi.流媒体在此类服务器中,环境必须设置为true。

要启用延迟响应,应用程序应该返回一个回调作为其响应。应用程序可能会检查psgi.流媒体环境是真实的,如果不是,则返回到直接响应。

将使用调用此回调另一个子程序参考(称为应答器从现在开始)作为唯一的论据。这个应答器应使用标准的三元素数组引用响应调用。这最好用一个例子来说明:

我的$app=sub{my$env=班次;#延迟响应,直到从网络中获取内容回流接头{我的$responder=班次;fetch_content_from_server(子{my$content=班次;$responder->([200,$headers,[$content]]);});};};

调用应答器.如果省略了正文,则应答器必须返回另一种实现的对象关闭方法。再一次,一个例子很好地说明了这一点。

我的$app=订阅{my$env=班次;#立即启动响应并传输内容回流接头{我的$responder=班次;我的$writer=$responser->([200,['Content-Type','application/json']]);等待事件(子{my$new_event=移位;if($new_event){$writer->write($new_event->as_json.“\n”);}其他{$writer->close;}});};};

如果您想实现基于非阻塞I/O的服务器流式传输或长轮询Comet推送技术,这种延迟响应和流式传输API非常有用,但也可以用于在阻塞服务器中实现无缓冲写入。

中间件

A类中间件组件接受另一个PSGI应用程序并运行它。从服务器的角度来看,中间件组件是一个PSGIS应用程序。从中间件组件运行的应用程序的角度来看,中间件就是服务器。通常,这样做是为了在PSGI环境散列上实现某种预处理或在响应上实现某种后处理。

下面是一个附加特殊HTTP头的简单示例X-PSGI使用任何PSGI应用程序。

#$app是一个简单的PSGI应用程序我的$app=订阅{my$env=移位;return[“200”,['内容类型'=>'text/plain'],[“Hello World”]];};#$xheader是封装$app的中间件my$xheader=子{my$env=班次;我的$res=$app->($env);按@{$res->[1],'X-PSGI-Used'=>1;返回$res;};

从服务器的角度来看,中间件的行为必须与PSGI应用程序完全相同。中间件可能决定不支持前面讨论的流接口,但应该传递它不理解的响应类型。

CHANGELOGS公司

1.1:2010.02.xx年1月1日

  • 添加了可选PSGI密钥作为扩展:psgix.记录器psgix.会话.

  • psgi.流媒体应该由PSGI服务器实现,而不是5月.

  • PSGI密钥psgi.运行一次(_O),psgi.非阻塞psgi.流媒体必须由PSGI服务器设置。

  • 远离的投票(_cb)作者方法。

致谢

本规范的某些部分采用了以下规范。

我要感谢这些伟大文件的作者。

作者

宫川达彦<miyagawa@bulknews.net>

贡献者

以下人员通过提交代码、发送补丁、报告错误、提问、建议有用的建议、吹毛求疵、在IRC上聊天或在我的博客上发表评论(无特定顺序),为PSGI规范和Plack实现做出了贡献:

松野德弘大泽和弘尤瓦尔·科格曼Kazuho Oku公司亚历克西斯·苏克里赫北野孝文斯特凡·利特尔大辅村社马拉佩德罗·梅洛杰西·卢尔斯约翰·贝普肖恩·莫尔马克·斯托斯伯格马特S鳟鱼杰西·文森特高嘉良戴夫·罗尔斯基汉斯·迪特尔·皮尔西兰迪·J·雷本杰明·特罗特Max Maischein公司奴隶Rezić马塞尔·格吕纳Masayoshi Sekimura先生布罗克·威尔科克斯Piers Cawley码头大辅町刘康民松本康弘柏林灰烬阿图尔·伯格曼西蒙·科岑斯斯科特·麦克沃特西口伸郎千叶Masahiro帕特里克·多尼兰保罗·德莱弗弗洛里安·拉格维茨

版权和许可

版权所有Tatsuhiko Miyagawa,2009-2011。

本文件由sa根据知识共享许可证进行许可。