连接、会话、请求、日志#
连接处理机制#
Angie 支持多种连接处理方法。特定方法的可用性取决于所使用的平台。在支持多种方法的平台上,Angie 通常会自动选择最高效的方法。但是,如有必要,可以使用 use 指令显式选择连接处理方法。
以下是可用的连接处理方法:
方法 | 描述 |
|---|---|
| 标准方法。在没有更高效方法的平台上会自动构建支持模块。可以使用 |
| 标准方法。在没有更高效方法的平台上会自动构建支持模块。可以使用 |
| 高效方法,可用于 FreeBSD 4.1+、OpenBSD 2.9+、NetBSD 2.0 和 macOS。 |
| 高效方法,可用于 Linux 2.6+。 |
| 高效方法,可用于 Solaris 7 11/99+、HP/UX 11.22+ (eventport)、IRIX 6.5.15+ 和 Tru64 UNIX 5.1A+。 |
|
|
HTTP 请求处理#
HTTP 请求会经历一系列阶段,在每个阶段执行特定类型的处理。
| 初始阶段。在此阶段调用 RealIP 模块。 |
| 处理 Rewrite 模块中定义在 |
| 特殊阶段,根据请求 URI 选择 location。 |
| 类似于 |
| 特殊阶段,如果在 |
| 在此阶段,标准 Angie 模块(如 Limit Req)注册它们的处理程序。 |
| 验证客户端是否有权发出请求的阶段,通常通过调用标准 Angie 模块(如 Auth Basic)来实现。 |
| 特殊阶段,处理 satisfy any 指令。 |
| |
| 通常生成响应的阶段。多个标准 Angie 模块在此阶段注册它们的处理程序,包括 Index。proxy_pass、fastcgi_pass、uwsgi_pass、scgi_pass 和 grpc_pass 指令也在此处理。 处理程序按顺序调用,直到其中一个产生输出。 |
| 最后阶段,执行请求日志记录。目前只有 Log 模块在此阶段注册其处理程序以进行访问日志记录。 |
TCP/UDP 会话处理#
来自客户端的 TCP/UDP 会话会经历一系列阶段,在每个阶段执行特定类型的处理:
| 接受客户端连接后的初始阶段。在此阶段调用 RealIP 模块。 |
| 检查访问权限的预备阶段。在此阶段调用 Set 模块。 |
| 在实际数据处理之前限制客户端访问的阶段。在此阶段调用 Access 模块。 |
| 发生 TLS/SSL 终止的阶段。在此阶段调用 SSL 模块。 |
| 将初始数据字节读入 预读缓冲区 的阶段,以允许模块(如 SSL Preread)在处理之前分析数据。 |
| 实际处理数据的强制阶段,通常涉及 Return 模块向客户端发送响应。proxy_pass 指令也在此处理。 |
| 记录客户端会话处理结果的最后阶段。在此阶段调用 Log 模块。 |
处理请求#
虚拟服务器选择#
最初,连接是在默认服务器的上下文中创建的。然后可以在请求处理的以下阶段确定服务器名称,每个阶段都参与服务器配置的选择:
在 SSL 握手期间,根据 SNI 提前确定。
处理请求行之后。
处理
Host头字段之后。
如果在处理请求行或 Host 头字段之后未确定服务器名称,Angie 将使用空名称作为服务器名称。
在这些阶段的每一个阶段,都可能应用不同的服务器配置。因此,某些指令应谨慎指定:
对于 ssl_protocols 指令,协议列表由 OpenSSL 库在根据通过 SNI 请求的名称应用服务器配置之前设置。因此,协议应仅为默认服务器指定。
client_header_buffer_size 和 merge_slashes 指令在读取请求行之前应用。因此,这些指令使用默认服务器配置或由 SNI 选择的服务器配置。
对于 ignore_invalid_headers、large_client_header_buffers 和 underscores_in_headers 指令,它们参与处理请求头字段,服务器配置还取决于是否根据请求行或
Host头字段进行了更新。错误响应使用当前正在处理请求的服务器中的 error_page 指令处理。
基于名称的虚拟服务器#
Angie 首先确定哪个服务器应该处理请求。考虑一个简单的配置,其中所有三个虚拟服务器都监听端口 80:
server {
listen 80;
server_name example.org www.example.org;
# ...
}
server {
listen 80;
server_name example.net www.example.net;
# ...
}
server {
listen 80;
server_name example.com www.example.com;
# ...
}
在此配置中,Angie 仅根据 Host 头字段确定哪个服务器应该处理请求。如果此头的值与任何服务器名称都不匹配,或者请求不包含此头字段,Angie 将把请求路由到此端口的默认服务器。在上面的配置中,默认服务器是第一个——这是 Angie 的标准默认行为。也可以使用 listen 指令中的 default_server 参数显式指定哪个服务器应该是默认服务器:
server {
listen 80 default_server;
server_name example.net www.example.net;
# ...
}
备注
请注意,默认服务器是监听套接字的属性,而不是服务器名称的属性。
国际化名称#
国际化域名(IDN)应在 server_name 指令中使用 ASCII(Punycode)表示形式指定:
server {
listen 80;
server_name xn--e1afmkfd.xn--80akhbyknj4f; # пример.испытание
# ...
}
阻止未定义服务器名称的请求#
如果不应允许没有 Host 头字段的请求,可以定义一个简单丢弃此类请求的服务器:
server {
listen 80;
server_name "";
return 444;
}
在此配置中,服务器名称设置为空字符串,它匹配没有 Host 头字段的请求。然后返回一个特殊的非标准代码 444,该代码会关闭连接。
组合基于名称和基于 IP 的虚拟服务器#
让我们来看一个更复杂的配置,其中一些虚拟服务器监听不同的地址:
server {
listen 192.168.1.1:80;
server_name example.org www.example.org;
# ...
}
server {
listen 192.168.1.1:80;
server_name example.net www.example.net;
# ...
}
server {
listen 192.168.1.2:80;
server_name example.com www.example.com;
# ...
}
在此配置中,Angie 首先根据 server 块的 listen 指令测试请求的 IP 地址和端口。然后,它根据匹配 IP 地址和端口的 server 块的 server_name 条目测试请求的 Host 头字段。如果未找到服务器名称,该请求将由默认服务器处理。例如,在端口 192.168.1.1:80 上接收到的对 www.example.com 的请求将由该端口的默认服务器处理——即第一个服务器——因为 www.example.com 未为此端口定义。
如前所述,默认服务器是监听端口的属性,可以为不同的端口定义不同的默认服务器:
server {
listen 192.168.1.1:80;
server_name example.org www.example.org;
# ...
}
server {
listen 192.168.1.1:80 default_server;
server_name example.net www.example.net;
# ...
}
server {
listen 192.168.1.2:80 default_server;
server_name example.com www.example.com;
# ...
}
选择位置#
考虑一个简单的PHP网站配置:
server {
listen 80;
server_name example.org www.example.org;
root /data/www;
location / {
index index.html index.php;
}
location ~* \.(gif|jpg|png)$ {
expires 30d;
}
location ~ \.php$ {
fastcgi_pass localhost:9000;
fastcgi_param SCRIPT_FILENAME
$document_root$fastcgi_script_name;
include fastcgi_params;
}
}
Angie 首先搜索由字面字符串给出的最具体的前缀 location,而不考虑它们的列出顺序。在上面的配置中,唯一的前缀 location 是 location /,它匹配任何请求,并将作为最后的选择。然后 Angie 按照配置文件中出现的顺序检查由正则表达式定义的 location。第一个匹配的表达式会停止搜索,Angie 将使用该 location。如果没有正则表达式匹配请求,Angie 将使用之前找到的最具体的前缀 location。
备注
所有类型的 location 仅测试请求行的 URI 部分,不包括参数。这是因为查询字符串中的参数可以以各种方式指定,例如:
/index.php?user=john&page=1/index.php?page=1&user=john
此外,查询字符串可能包含任意数量的参数:
/index.php?page=1&something+else&user=john
现在让我们看看在上述配置中如何处理请求:
请求
/logo.gif首先由前缀location /匹配,然后由正则表达式.(gif|jpg|png)$匹配。因此,它由后者 location 处理。使用指令root /data/www,请求被映射到文件/data/www/logo.gif,并将文件发送给客户端。请求
/index.php也首先由前缀location /匹配,然后由正则表达式.(php)$匹配。因此,它由后者 location 处理,请求被传递到监听localhost:9000的 FastCGI 服务器。fastcgi_param 指令将 FastCGI 参数SCRIPT_FILENAME设置为/data/www/index.php,FastCGI 服务器执行该文件。变量 $document_root 设置为root指令的值,变量 $fastcgi_script_name 设置为请求 URI,即/index.php。请求
/about.html仅由前缀location /匹配,因此在此 location 中处理。使用指令root /data/www,请求被映射到文件/data/www/about.html,并将文件发送给客户端。
处理请求 / 更为复杂。它仅由前缀 location / 匹配,因此由此 location 处理。然后 index 指令根据其参数和 root /data/www 指令测试索引文件是否存在。如果文件 /data/www/index.html 不存在但文件 /data/www/index.php 存在,该指令执行到 /index.php 的内部重定向,Angie 再次搜索 location,就像请求是由客户端发送的一样。如前所述,重定向的请求最终将由 FastCGI 服务器处理。
代理和负载均衡#
Angie 的一个常见用途是将其设置为代理服务器。在此角色中,Angie 接收请求,将它们转发到被代理的服务器,从这些服务器检索响应,并将响应发送回客户端。
一个简单的代理服务器:
server {
location / {
proxy_pass http://backend:8080;
}
proxy_pass 指令指示 Angie 将客户端请求传递给后端 Angie 可用于将请求路由到运行使用各种框架和编程语言(如 PHP)构建的应用程序的 FastCGI 服务器。 与 FastCGI 服务器配合使用的最基本的 Angie 配置涉及使用 fastcgi_pass 指令代替 proxy_pass 指令,以及使用 fastcgi_param 指令设置传递给 FastCGI 服务器的参数。假设 FastCGI 服务器可在 此配置设置了一个服务器,该服务器将所有请求(静态图像请求除外)通过 FastCGI 协议路由到在 要将连接从 HTTP/1.1 升级到 WebSocket,需要使用 HTTP/1.1 中提供的`协议切换
<https://datatracker.ietf.org/doc/html/rfc2616#section-14.42>`_机制。 然而,这里有一个微妙之处:由于 Angie 实现了一种特殊的操作模式,如果被代理的服务器返回代码为 101(切换协议)的响应,并且客户端通过请求中的 如前所述,逐跳头(包括 一个更复杂的示例演示了如何根据客户端请求头中是否存在 默认情况下,如果被代理的服务器在 60 秒内没有传输任何数据,连接将被关闭。可以使用 proxy_read_timeout 指令增加此超时时间。或者,可以将被代理的服务器配置为定期发送 WebSocket ping 帧以重置超时并检查连接是否仍然活动。 在多个应用程序实例之间进行负载均衡是一种广泛使用的技术,用于优化资源利用率、最大化吞吐量、减少延迟并确保容错配置。 Angie 可以用作高效的 HTTP 负载均衡器,将流量分配到多个应用程序服务器,从而提高 Web 应用程序的性能、可扩展性和可靠性。 使用 Angie 进行负载均衡的最简单配置可能如下所示: 在上面的示例中,同一应用程序的三个实例分别运行在 backend:8080 (被代理的服务器)。还有许多其他 指令 可用于进一步配置代理连接。FastCGI 代理#
localhost:9000 访问。在 PHP 中,SCRIPT_FILENAME 参数用于确定脚本名称,QUERY_STRING 参数用于传递请求参数。生成的配置如下:server {
location / {
fastcgi_pass localhost:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param QUERY_STRING $query_string;
}
location ~ \.(gif|jpg|png)$ {
root /data/images;
}
}
localhost:9000 上运行的被代理服务器。WebSocket 代理#
Upgrade 头是一个`逐跳头
<https://datatracker.ietf.org/doc/html/rfc2616#section-13.5.1>`_,它不会从客户端传递到被代理的服务器。在正向代理中,客户端可以使用 CONNECT 方法来规避这个问题。但这种方法不适用于反向代理,因为客户端不知道任何代理服务器的存在,需要在代理服务器上进行特殊处理。Upgrade 头请求协议切换,则允许在客户端和被代理服务器之间建立隧道。Upgrade 和 Connection)不会从客户端传递到被代理的服务器。因此,为了让被代理的服务器知道客户端切换到 WebSocket 协议的意图,必须显式传递这些头:location /chat/ {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
Upgrade 字段,来决定发送到被代理服务器的请求中 Connection 头字段的值:http {
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
...
location /chat/ {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
}
负载均衡#
http {
upstream myapp1 {
server srv1.example.com;
server srv2.example.com;
server srv3.example.com;
}
server {
listen 80;
location / {
proxy_pass http://myapp1;
}
}
}
srv1 到 srv3 上。当没有显式配置负载均衡方法时,默认使用轮询。其他支持的负载均衡机制包括:weight、least_conn 和 ip_hash。Angie 中的反向代理实现还支持带内(或被动)服务器健康探测。这些探测使用 upstream 上下文中 server 块内的 max_fails 和 fail_timeout 指令进行配置。
日志记录#
备注
除了此处列出的选项外, 您还可以启用 调试日志。
Syslog#
error_log 和 access_log 指令支持记录到 syslog。以下参数用于配置到 syslog 的日志记录:
| 指定 |
| 设置 |
| 定义 access_log 的 |
| 设置 |
| 禁止在 |
syslog 配置示例:
error_log syslog:server=192.168.1.1 debug;
access_log syslog:server=unix:/var/log/angie.sock,nohostname;
access_log syslog:server=[2001:db8::1]:12345,facility=local7,tag=angie,severity=info combined;
备注
为防止泛滥,Syslog 条目每秒最多报告一次。