连接、会话、请求、日志#
连接处理机制#
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 模块。 |
|
在此阶段处理 |
|
一个特殊阶段,根据请求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 模块。 |
|
将初始数据字节读入 preread buffer 的阶段,以允许模块如 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;
# ...
}
备注
请注意,默认服务器是监听套接字的属性,而不是服务器名称的属性。
国际化名称#
国际化域名(IDNs) 应在 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首先测试请求的IP地址和端口与 server 块的 listen 指令进行匹配。然后测试请求的 Host
头字段与匹配IP地址和端口的 server 块的 server_name 条目进行匹配。如果未找到服务器名称,请求将由默认服务器处理。例如,收到的请求 www.example.com
在端口192.168.1.1:80上将由该端口的默认服务器处理——即第一个服务器——因为 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 /
,它匹配任何请求,并将作为最后的手段使用。然后,Angie按配置文件中出现的顺序检查由正则表达式定义的位置。第一个匹配的表达式停止搜索,Angie将使用该 location
。如果没有正则表达式匹配请求,Angie将使用之前找到的最具体的前缀 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)$
。因此,它由后者位置处理。使用指令root /data/www
,请求映射到文件/data/www/logo.gif
,并将文件发送给客户端。请求
/index.php
也首先匹配前缀location /
,然后匹配正则表达式.(php)$
。因此,它由后者位置处理,请求被传递到监听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 /
,因此在此位置处理。使用指令root /data/www
,请求映射到文件/data/www/about.html
,并将文件发送给客户端。
处理请求 / `更为复杂。它仅匹配前缀 `location /
,因此在此位置处理。index 指令然后根据其参数和 root /data/www
指令测试索引文件的存在。如果文件 /data/www/index.html
不存在但文件 /data/www/index.php
存在,该指令执行内部重定向到 /index.php
,Angie再次搜索位置,仿佛请求是由客户端发送的。如前所述,重定向的请求最终将由FastCGI服务器处理。
代理和负载均衡#
设置Angie作为代理服务器是一个常见用途。在此角色中,Angie接收请求,将它们转发到代理服务器,检索来自这些服务器的响应,并将响应发送回客户端。
一个简单的代理服务器:
server {
location / {
proxy_pass http://backend:8080;
}
proxy_pass 指令指示Angie将客户端请求传递给后台 backend:8080
代理服务器)。还有许多额外的 directives 可用于进一步配置代理连接。
FastCGI代理#
Angie可以用于将请求路由到运行各种框架和编程语言(如PHP)的FastCGI服务器。
与FastCGI服务器一起工作的最基本的Angie配置涉及使用 fastcgi_pass 指令而不是 proxy_pass 指令,并使用 fastcgi_param 指令设置传递给FastCGI服务器的参数。假设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;
}
}
此配置设置了一个服务器,通过FastCGI协议将除静态图像之外的所有请求路由到在 localhost:9000
上运行的代理服务器。
WebSocket代理#
要从HTTP/1.1升级连接到WebSocket,使用HTTP/1.1中可用的 协议切换 机制。
不过,这里有一个细微之处:由于 Upgrade
头是一个`逐跳头 <https://datatracker.ietf.org/doc/html/rfc2616#section-13.5.1>`_,它不会从客户端传递到代理服务器。对于正向代理,客户端可以使用CONNECT方法来规避此问题。此方法不适用于反向代理,因为客户端不知道任何代理服务器,并且需要在代理服务器上进行特殊处理。
Angie实现了一种特殊的操作模式,允许在客户端和代理服务器之间建立隧道,如果代理服务器返回代码101(协议切换)的响应,并且客户端通过请求中的 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";
}
更复杂的示例演示了在向代理服务器的请求中 Connection
头字段的值如何依赖于客户端请求头中的 Upgrade
字段的存在:
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;
}
}
}
默认情况下,如果代理服务器在60秒内没有传输任何数据,连接将关闭。可以使用 proxy_read_timeout 指令增加此超时。或者,可以配置代理服务器定期发送WebSocket ping帧以重置超时并检查连接是否仍然活动。
负载均衡#
跨多个应用实例进行负载均衡是一种广泛使用的技术,以优化资源利用,最大化吞吐量,减少延迟,并确保容错配置。
Angie可以用作高效的HTTP负载均衡器,将流量分配到多个应用服务器,从而提高Web应用程序的性能、可扩展性和可靠性。
使用Angie进行负载均衡的最简单配置可能如下所示:
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 指令进行配置。
日志记录#
备注
除了这里列出的选项外,还可以启用 debugging log。
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条目每秒报告不超过一次。