<!-- review: finished -->

<a id="http-perl"></a>

# Perl

该模块允许在 Perl 中编写位置和变量处理器，以及将 Perl 调用插入到 SSI 中。

当 [从源代码构建](https://cn.angie.software//angie/docs/installation/sourcebuild.md#sourcebuild) 时，
该模块默认不构建；
应通过
`‑‑with‑http_perl_module`
[构建选项](https://cn.angie.software//angie/docs/installation/sourcebuild.md#configure) 启用。

在我们的代码库中，该模块是
[动态构建](https://cn.angie.software//angie/docs/installation/index.md#install-dynamicmodules)
并作为一个名为 `angie-module-perl` 或 `angie-pro-module-perl` 的单独软件包提供；
可以使用 [load_module](https://cn.angie.software//angie/docs/configuration/modules/core.md#load-module) 指令加载。

#### NOTE
此模块需要 Perl 版本 5.6.1 或更高版本。C 编译器应与用于构建 Perl 的编译器兼容。

<a id="known-issues"></a>

## 已知问题

该模块是实验性的，因此任何情况都可能发生。

为了让 Perl 在重新配置期间重新编译修改过的模块，
应使用 `-Dusemultiplicity=yes` 或
`-Dusethreads=yes` 参数构建。此外，为了减少 Perl 在运行时的内存泄漏，应使用 `-Dusemymalloc=no` 参数进行构建。要检查已构建 Perl 的这些参数的值（示例中指定了首选值），请运行：

```console
$ perl -V:usemultiplicity -V:usemymalloc
usemultiplicity='define';
usemymalloc='n';
```

请注意，在使用新的 `-Dusemultiplicity=yes` 或
`-Dusethreads=yes` 参数重新构建 Perl 后，所有二进制 Perl 模块也必须重新构建——它们将不再与新的 Perl 兼容。

主进程和工作进程的大小在每次重新配置后可能会增长。如果主进程增长到不可接受的大小，可以在不更改可执行文件的情况下应用 [实时升级](https://cn.angie.software//angie/docs/configuration/runtime.md#service-upgrade) 程序。

当 Perl 模块执行长时间运行的操作时，例如解析域名、连接到其他服务器或查询数据库，分配给当前工作进程的其他请求将不会被处理。因此，建议仅执行具有可预测且短执行时间的操作，例如访问本地文件系统。

<a id="configuration-example-32"></a>

## 配置示例

```nginx
http {

    perl_modules perl/lib;
    perl_require hello.pm;

    perl_set $msie6 '

        sub {
            my $r = shift;
            my $ua = $r->header_in("User-Agent");

            return "" if $ua =~ /Opera/;
            return "1" if $ua =~ / MSIE [6-9]\.\d+/;
            return "";
        }

    ';

    server {
        location / {
            perl hello::handler;
        }
    }
```

perl/lib/hello.pm 模块：

```perl
package hello;

use nginx;

sub handler {
    my $r = shift;

    $r->send_http_header("text/html");
    return OK if $r->header_only;

    $r->print("hello!\n<br/>");

    if (-f $r->filename or -d _) {
        $r->print($r->uri, " exists!\n");
    }

    return OK;
}

1;
__END__
```

<a id="directives-33"></a>

## 指令

<a id="index-0"></a>

<a id="id4"></a>

### perl

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `perl` module :: function | 'sub { ... }';   |
|--------------------------------------------------------------------------------------|----------------------------------------------|
| 默认                                                                                   | —                                            |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | location, limit_except                       |

为给定位置设置一个 Perl 处理器。

<a id="index-1"></a>

<a id="perl-modules"></a>

### perl_modules

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `perl_modules` path;   |
|--------------------------------------------------------------------------------------|------------------------|
| 默认                                                                                   | —                      |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | http                   |

为 Perl 模块设置额外路径。

<a id="index-2"></a>

<a id="perl-require"></a>

### perl_require

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `perl_require` module;   |
|--------------------------------------------------------------------------------------|--------------------------|
| 默认                                                                                   | —                        |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | http                     |

定义将在每次重新配置时加载的模块名称。可以存在多个 perl_require 指令。

<a id="index-3"></a>

<a id="perl-set"></a>

### perl_set

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `perl_set` $variable module :: function | 'sub { ... }';   |
|--------------------------------------------------------------------------------------|------------------------------------------------------------|
| 默认                                                                                   | —                                                          |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | http                                                       |

为指定变量设置一个 Perl 处理器。

<a id="calling-perl-from-ssi"></a>

## 从 SSI 调用 Perl

调用 Perl 的 SSI 命令具有以下格式：

```html
<!--# perl sub="module::function" arg="parameter1" arg="parameter2" ...
-->
```

<a id="the-r-request-object-methods"></a>

## $r 请求对象方法

<a id="samp-r-args"></a>

### `$r->args`

返回请求参数。

<a id="samp-r-filename"></a>

### `$r->filename`

返回与请求 URI 对应的文件名。

<a id="samp-r-has-request-body-handler"></a>

### `$r->has_request_body` (handler)

如果请求中没有主体，则返回 0。如果有主体，则为请求设置指定的处理器并返回 1。在读取请求主体后，Angie 将调用指定的处理器。请注意，处理器函数应以引用方式传递。示例：

```perl
package hello;

use nginx;

sub handler {
    my $r = shift;

    if ($r->request_method ne "POST") {
        return DECLINED;
    }

    if ($r->has_request_body(\&post)) {
        return OK;
    }

    return HTTP_BAD_REQUEST;
}

sub post {
    my $r = shift;

    $r->send_http_header;

    $r->print("request_body: \"", $r->request_body, "\"<br/>");
    $r->print("request_body_file: \"", $r->request_body_file, "\"<br/>\n");

    return OK;
}

1;

__END__
```

<a id="samp-r-allow-ranges"></a>

### `$r->allow_ranges`

启用在发送响应时使用字节范围。

<a id="samp-r-discard-request-body"></a>

### `$r->discard_request_body`

指示 Angie 丢弃请求主体。

<a id="samp-r-header-in-field"></a>

### `$r->header_in` (field)

返回指定客户端请求头字段的值。

<a id="samp-r-header-only"></a>

### `$r->header_only`

确定是否应将整个响应或仅其头部发送到客户端。

<a id="samp-r-header-out-field-value"></a>

### `$r->header_out` (field, value)

为指定响应头字段设置一个值。

<a id="samp-r-internal-redirect-uri"></a>

### `$r->internal_redirect` (uri)

对指定的 uri 进行内部重定向。实际重定向在 Perl 处理器执行完成后发生。该方法接受转义的 URI，并支持重定向到 [命名位置](https://cn.angie.software//angie/docs/configuration/modules/http/index.md#named-location)。

<a id="samp-r-log-error-errno-message"></a>

### `$r->log_error` (errno, message)

将指定消息写入 [error_log](https://cn.angie.software//angie/docs/configuration/modules/core.md#error-log)。如果 errno 非零，错误代码及其描述将附加到消息中。

<a id="samp-r-print-text"></a>

### `$r->print` (text, ...)

将数据传递给客户端。

<a id="samp-r-request-body"></a>

### `$r->request_body`

如果客户端请求主体尚未写入临时文件，则返回客户端请求主体。为了确保客户端请求主体在内存中，其大小应通过 [client_max_body_size](https://cn.angie.software//angie/docs/configuration/modules/http/index.md#client-max-body-size) 限制，并使用 [client_body_buffer_size](https://cn.angie.software//angie/docs/configuration/modules/http/index.md#client-body-buffer-size) 设置足够的缓冲区大小。

<a id="p-r-request-body-file"></a>

### `$r->request_body_file`

返回包含客户端请求主体的文件名称。处理后，应删除该文件。要始终将请求主体写入文件，应启用 [client_body_in_file_only](https://cn.angie.software//angie/docs/configuration/modules/http/index.md#client-body-in-file-only)。

<a id="samp-r-request-method"></a>

### `$r->request_method`

返回客户端请求的 HTTP 方法。

<a id="samp-r-remote-addr"></a>

### `$r->remote_addr`

返回客户端 IP 地址。

<a id="samp-r-flush"></a>

### `$r->flush`

立即将数据发送给客户端。

<a id="samp-r-sendfile-name-offset-length"></a>

### `$r->sendfile` (name [, offset [, length ]])

将指定文件内容发送给客户端。可选参数指定数据传输的初始偏移量和长度。实际数据传输在 Perl 处理器完成后发生。

<a id="samp-r-send-http-header-type"></a>

### `$r->send_http_header` ([type])

将响应头发送给客户端。可选的类型参数设置 `Content-Type` 响应头字段的值。如果值为空字符串，则将不发送 `Content-Type` 头字段。

<a id="samp-r-status-code"></a>

### `$r->status` (code)

设置响应代码。

<a id="samp-r-sleep-milliseconds-handler"></a>

### `$r->sleep` (milliseconds, handler)

设置指定的处理器，并在指定时间内停止请求处理。在此期间，Angie 继续处理其他请求。在指定时间经过后，Angie 将调用安装的处理器。请注意，处理器函数应以引用方式传递。为了在处理器之间传递数据，应使用 [$r‑>variable()](#p-r-variable)。示例：

```nginx
package hello;

use nginx;

sub handler {
    my $r = shift;

    $r->discard_request_body;
    $r->variable("var", "OK");
    $r->sleep(1000, \&next);

    return OK;
}

sub next {
    my $r = shift;

    $r->send_http_header;
    $r->print($r->variable("var"));

    return OK;
}

1;

__END__
```

<a id="samp-r-unescape-text"></a>

### `$r->unescape` (text)

解码以 "%XX" 形式编码的文本。

<a id="samp-r-uri"></a>

### `$r->uri`

返回请求 URI。

<a id="p-r-variable"></a>

### `$r->variable` (name [, value ])

返回或设置指定变量的值。变量对每个请求都是本地的。
