7、nginx模块之HTTP模块(1)

发布时间 2024-01-09 16:31:12作者: ccblblog

1、概述

  • 静态Web服务器的主要功能由ngx_http_core_module模块实现,一个完整的静态 Web 服务器还有许多功能是由其他的 HTTP 模块实现的。
  • 一个典型的静态 Web 服务器包含多个 server 块和location 块,例如:
http {
   gzip on;
   
   upstream {
        ...
    }
    ...
    server {
       		listen localhost:80;
        	...
        	location /webstatic {
            		if ... {
                			...
            		}
            		root /opt/webresource;
            		...
        	}
        location ~* .(jpg|jpeg|png|jpe|gif)${
            ...
        } 
    }
    server {
            ...
    }
}

所有的HTTP配置项都必须直属于 http 块、server 块、location 块、upstream 块或if块等,同时,在描述每个配置项的功能时,会说明它可以在上述的哪个块中存在,因为有些配置项可以任意地出现在某一个块中,而有些配置项只能出现在特定的块中。

2. Nginx 提供的功能

Nginx为配置一个完整的静态 Web 服务器提供了非常多的功能

  • 虚拟主机与请求的分发
  • 文件路径的定义
  • 内存及磁盘资源的分配
  • 网络连接的设置
  • MIME 类型的设置
  • 对客户端请求的限制
  • 文件操作的优化
  • 对客户端请求的特殊处理

2.1 虚拟主机与请求的分发

由于 IP 地址的数量有限,因此经常存在多个主机域名对应着同一个 IP 地址的情况,这时在 nginx.conf 中就可以按照server_name(对应用户请求中的主机域名)并通过server块来定义虚拟主机,每个 server 块就是一个虚拟主机,它只处理与之相对应的主机域名请求。这样,一台服务器上的 Nginx 就能以不同的方式处理访问不同主机域名的 HTTP 请求了。

2.1.1 监听端口

语法: listen address:port [default] | default_server | [ backlog=num | rcvbuf=size | sndbuf=size | accept_filter=filter | deferred | bind | ipv6only=[on|off] ssl]];
默认: listen 80;
配置块: server

  • listen 参数决定Nginx 服务如何监听端口。在listen 后可以只加IP 地址、端口或主机名非常灵活,例如:

    listen 127.0.0.1:8000;
    
    #注意:不加端口时,默认监听 80端口
    listen 127.0.0.1;
    
    listen 8000;
    listen *:8000;
    listen localhost:8000;
    
  • 如果服务器使用 IPv6 地址,那么可以这样使用:

    listen [::]:8000;
    listen [fe80::1];
    listen [:::a8c9:1234]:80;
    
    • 在地址和端口后,还可以加上其他参数,例如:

      listen 443 default_server ssl;
      listen 127.0.0.1 default_server accept_filter=dataready backlog=1024;
      
      

default: 将所在的 server 块作为整个 Web 服务的默认 server 块。如果没有设置这个参数,那么将会以在nginx.conf中找到的第一个 server 块作为默认 server 块。为什么需要默认虚拟主机呢?当一个请求无法匹配配置文件中的所有主机域名时,就会选用默认的虚拟主机。

default_server: 同上。

backlog=num: 表示TCP 中 backlog(积压) 队列的大小。默认为-1,表示不予设置。在TCP建立三次握手过程中,进程还没有开始处理监听句柄,这时 backlog 队列将会放置这些新连接。可如果 backlog 队列已满,还有新的客户端试图通过三次握手建立TCP连接,这时客户端将会建立连接失败。

rcvbuf=size: 设置监听句柄的SO_RCVBUF参数

sndbuf==size: 设置监听柄的SO_SNDBUF 参数

accept_filter: 设置 accept 过滤器,只对 FreeBSD 操作系统有用

deferred: 在设置该参数后,若用户发起建立连接请求,并且完成了 TCP 的三次握手,内核也不会为了这次的连接调度 worker 进程来处理,只有用户真的发送请求数据时(内核已经在网卡中收到请求数据包),内核才会唤醒 worker 进程处理这个连接。这个参数适用于大并发的情况下,它减轻了 worker 进程的负担。当请求数据来临时worker 进程才会开始处理这个连接。只有确认上面所说的应用场景符合自己的业务需求时,才可以使用deferred 配置。
bind: 绑定当前端口/地址对,如 127.0.0.1:8000。只有同时对一个端口监听多个地址时才会生效

ssl: 在当前监听的端口上建立的连接必须基于SSL 协议。

2.1.2 主机名称

语法: server_name name [...];

默认: server_name "";

配置块: server

  • server_name 后可以跟多个主机名称,如:

     server_name www.testweb.com download.testweb.com;
    
  • 在开始处理一个HTTP请求时,Nginx会取出 header 头中的Host,与每个server中的server_name进行匹配,以此决定到底由哪一个 server块来处理这个请求。

  • 有可能一个Host与多个 server块中的 server_name 都匹配,这时就会根据匹配优先级来选实际处理的server 块。

  • server_name 与 Host 的匹配优先级如下

    1. 首先选择所有字符串完全匹配的 server_name,如 www.testweb.com
    2. 其次选择通配符在前面的 server_name,如*.testweb.com
    3. 再次选择通配符在后面的 server_name,如www.testweb.*
    4. 最后选择使用正则表达式才匹配的 server_name,如~^\.testweb\.com$
  • 如果 Host 与所有的 server_name 都不匹配,这时将会按下列顺序选择处理的server块

    1. 优先选择在listen 配置项后加入[default|default_server]的 server块。
    2. 找到匹配 listen 端口的第一个 server 块。如果server_name后跟着空字符串(如 server_name"?,那么表示匹配没有 Host 这个HTTP头部的请求。

注意 Nginx 正是使用server_name 配置项针对特定 Host 域名的请求提供不同的服务,以此实现虚拟主机功能。

2.1.3 主机名称hash_bucket

语法: server_names_hash_bucket_size size;

默认:server_names_hash_bucket_size 32|64|128;

配置块: http、server、location

  • 为了提高快速寻找到相应server_name的能力,Nginx使用散列表来存储server_name。server_names_hash bucket_size 设置了每个散列桶占用的内存大

2.1.4 主机名称hash_max

语法: server_names_hash_max_size size:
默认: server_names_hash_max_size 512;
配置块: http、server、location

  • server_names_hash_max_size 会影响散列表的冲突率。server_names_hash_max_size 越消耗的内存就越多,但散列 key 的冲突率则会降低,检索速度也更快。server_names_hash_max_size 越小,消耗的内存就越小,但散列 key 的冲突率可能增高。

2.1.5重定向主机名称的处理

语法: server_name_in_redirect on | off;
默认: server_name_in_redirect on;
配置块: http、server、 location

  • 该配置需要配合 server_name使用。在使用on打开时,表示在重定向请求时会使用server_name里配置的第一个主机名代替原先请求中的Host头部,而使用off关闭时,表示在重定向请求时使用请求本身的 Host 头部。

2.1.6 location

语法: location [=||*|^~|@]/uri/ { ...}
配置块:server

  • location会尝试根据用户请求中的URI来匹配上面的/uri表达式,如果可以匹配,就选择 location 块中的配置来处理用户请求。当然,匹配方式是多样的,

  • location的匹配规则

    1. = 表示把URI作为字符串,以便与参数中的 uri 做完全匹配。例如:

      location = / {
      	# 只有当用户请求是/时,才会使用该 location 下的配置
      	...
      }
      
      
    2. ~ 表示匹配URI时是字母大小写敏感的。

    3. ~*表示匹配URI时忽略字母大小写问题。

    4. ^~表示匹配URI时只需要其前半部分与uri参数匹配即可。例如:

      location ^~ /images/ {
          #  以 /images/ 开始的请求都会匹配上
      }
      
    5. @表示仅用于Nginx服务内部请求之间的重定向,带有@的location 不直接处理用户请求。当然,在uri参数里是可以用正则表达式的,例如:

      location  ~* \.(gif|jpg|jpeg)$ {
          # 匹配以.gif、.jpg、.jpeg 结尾的请求  
          ...
      } 
      

      注意,location 是有顺序的,当一个请求有可能匹配多个 location 时,实际上这个请求会被第一个location 处理。
      在以上各种匹配方式中,都只能表达为如果匹配...则...。如果需要表达如果不配..则...,就很难直接做到。有一种解决方法是在最后一个 location 中使用/作为参数它会匹配所有的 HTTP 请求,这样就可以表示如果不能匹配前面的所有 location,则由/这个location 处理。例如:

      location / {
      	# / 可以匹配所有请求
      	...
      }
      

2.2文件路径的定义

2.2.1 以root方式设置资源路径

语法:root path;
默认:root html;
配置块: http、server、location、if

  • 定义资源文件相对于 HTTP 请求的根目录

    location /download/ {
        root /opt/web/html/;
    }
    
  • 在上面的配置中,如果有一个请求的URI是 /download/index/test.html,那么Web 服务器将会返回服务器上/opt/web/html/download/index/test.html文件的内容。

2.2.2 以alias 方式设置资源路径

语法: alias path;
配置块: location

  • alias 也是用来设置文件资源路径的,它与 root 的不同点主要在于如何解读紧跟 location 后面的uri参数,这将会致使 alias 与root 以不同的方式将用户请求映射到真正的磁盘文件上。

  • 一个请求的URI是/conf/nginx.conf,而用户实际想访问的文在/usr/local/nginx/conf/nginx.conf,那么想要使用alias 来进行设置的话,可以采用如下方式:

    location /conf {
        alias /usr/local/nginx/conf/;
    }
    
  • 如果用 root 设置,那么语句如下所示:

    location /conf {
        root /usr/local/nginx/;
    }
    

使用 alias 时,在URI向实际文件路径的映射过程中,已经把location后配置的/conf 这部分字符串丢弃掉,因此,/conf/nginx.conf请求将根据alias path映射为 path/nginx.conf。这也是 root 可以放置到 httpserverlocationif块中,而 alias 只能放置到location 块中的原因.

  • alias后面还可以添加正则表达式,例如:

    location ~ ^/test/(w+).(w+)$ {
       alias /usr/local/nginx/$2/$1.$2;  
    } 
    

    这样,请求在访问/test/nginx.conf时,Nginx会返回 /usr/local/nginx/conf/nginx.conf文件中的内容。

2.2.3 访问首页

语法: index file ...;

默认: index index.html;

配置块: http、server、location

  • 当访问的URI是/,一般返回网站的首页,而这与rootalias 都不同。这里用ngx_http_index_module 模块提供的index配置实现。index后可以跟多个文件参数,Nginx 将会按照顺序来访问这些文件,例如:

    location / {
        root path;
        index /index.html /html/index.php /index.php;
    }
    
  • 接收到请求后,Nginx 首先会尝试访问 path/index.php 文件,如果可以访问,就直接返回文件内容结束请求,否则再试图返回 path/html/index.php 文件的内容,依此类推。

2.2.4 根据HTTP 返回码重定向页面

语法: error_page code [ code...] [ =|=answer-code ] uri | @named_location

配置块: http、server、location、if

  • 当对于某个请求返回错误码时,如果匹配上了error_page 中设置的 code,则重定向到新的URI中。例如:
error_page 404 			/404.html;
error_page 502 503 504  /50x.html;
error_page 403          http://example.com/forbidden.html;
error_page 404          = @fetch;
  • 注意,虽然重定向了URI,但返回的 HTTP 错误码还是与原来的相同。用户可以通过=来更改返回的错误码,例如:

    error_page 404 =200 /empty.gif;
    error_page 404 =403 /forbidden.gif;
    
  • 也可以不指定确切的返回错误码,而是由重定向后实际处理的真实结果来决定,这时,只要把=后面的错误码去掉即可,例如:

    error_page 404 = /empty.gif;
    
  • 如果不想修改URI,只是想让这样的请求重定向到另一个location 中进行处理,那么可以这样设置:

    location / (
      error_page 404 @fallback;
    )
    
    location @fallback (
    	proxy_pass http://backend;  
    }
    

    这样,返回404的请求会被反向代理到 http://backend 上游服务器中处理。

2.2.5 是否允许递归使用error_page

语法: recursive_error_pages [on off];
默认: recursive_error_pages off;
配置块: http、server、location

  • 确定是否允许递归地定义error page。

2.2.6 try_files

语法: try_files path1 [path2] uri;
配置块: server、location

  • try_files 后要跟若干路径,如 path1 path2...,而且最后必须要有 uri参数,意义如下: 尝试按照顺序访问每一个 path,如果可以有效地读取,就直接向用户返回这个 path 对应的文件结束请求,否则继续向下访问。

  • 如果所有的 path 都找不到有效的文件,就重定向到最后的参数 uri上。因此,最后这个参数 uri 必须存在,而且它应该是可以有效重定向的。例如:

    try_files /system/maintenance.html $uri $uri/index.html $uri.html @other;
    location @other {
        proxy_pass http://backend;
    }
    

    上面这段代码表示如果前面的路径,如/system/maintenance.html等,都找不到,就会反向代理到 http://backend 服务上。

  • 还可以用指定错误码的方式与error_page 配合使用,例如:

    location / {
       try_files $uri $uri/ /error.php?c=404 =404; 
    }
    
    

2.3 内存及磁盘资源的分配

2.3.1 HTTP包体只存储到磁盘文件中

语法: client_body_in_file_only on|clean|off;
默认: client_body_in_file_only off;
配置块: http、server、location

  • 当值为非off时,用户请求中的 HTTP 包体一律存储到磁盘文件中,即使只有0字节也会存储为文件。
  • 当请求结束时,如果配置为 on,则这个文件不会被删除(该配置一般用于调试、定位问题),
  • 如果配置为 clean,则会删除该文件。

2.3.2 HTTP包体写入到内存 buffer 中

语法: client_body_in_single_buffer on|off;

默认: client_body_in_single_buffer off;

配置块: http、server、location

  • 请求中的HTTP 包体存储到内存 buffer 中。如果HTTP 包体的大小超过了client_body_buffer_ size 设置的值,包体还是会写入到磁盘文件中。

2.3.3 存储HTTP头部的内存 buffer 大小

语法: client_header_buffer_size size;
默认: client_header_buffer_size 1k;
配置块: http、server

  • 配置项定义了正常情况下Nginx 接收用户请求中HTTP header 部分(包括HTTP行和HTTP头部)时分配的内存 buffer 大小。
  • 请求中的HTTP header 部分可能会超过这个大小,这时 large_client_header_buffers 定义的 buffer 将会生效。

2.3.4 存储超大HTTP头部的内存 buffer 大小

语法: large_client_header_buffers number size;
默认: large client header buffers 4 8k;
配置块: http、server

  • large_client_header_buffers 定义了Nginx 接收一个超大HTTP 头部请求的 buffer 个数和每个buffer 的大小。
  • 如果HTTP 请求行(如GET /index HTTP/1.1)的大小超过上面的单个buffer,则返回Request URI too large(414)。
  • 请求中一般会有许多header,每一个 header的大小也不能超过单个 buffer 的大小,否则会返回Bad request(400)。当然,请求行和请求头部的总和也不可以超过 buffer 个数 *buffer 大小

2.3.5 存储HTTP包体的内存 buffer 大小

语法: client_body_buffer_size size;
默认:client_body_buffer_size 8k/16k;
配置块: http、server、location

  • 配置项定义了Nginx 接收 HTTP 包体的内存缓冲区大小。也就是说,HTTP 包体会先接收到指定的这块缓存中,之后才决定是否写入磁盘。

注意 如果用户请求中含有HTTP 头部 Content-Length,并且其标识的长度小于定义的buffer 大小,那么Nginx 会自动降低本次请求所使用的内存 buffer,以降低内存消耗。

2.3.6 HTTP包体的临时存放目录

语法: client body_temp_path dir-path [ level1 [ level2 [ level3 ]l]
默认:client body temp path client body_temp;
配置块: http、server、location

  • 配置项定义 HTTP 包体存放的临时目录。在接收 HTTP 包体时,如果包体的大小大于client_body_buffer_size,则会以一个递增的整数命名并存放到 client_body_temp_path指定的目录中

  • level1、level2、level3是为了防止一个目录下的文件数量太多从而导致性能下降,因此使用了 level参数,这样可以按照临时文件名最多再加三层目录。例如:

client_body_temp_path /opt/nginx/client_temp 1 2;

如果新上传的HTTP 包体使用00000123456作为临时文件名,就会被存放在这个目录中
/opt/nginx/client_temp/6/45/00000123456

2.3.7 connection_pool_size

语法: connection_pool_size size;
默认: connection_pool_size 256
配置块: http、server

  • Nginx对于每个建立成功的TCP 连接会预先分配一个内存池,上面的 size 配置项将指定这个内存池的初始大小(即ngx_connection_t 结构体中的 pool 内存池初始大小),用于减少内核对于小块内存的分配次数。需慎重设置,因为更大的 size 会使服务器消耗的内存增多,而更小的 size 则会引发更多的内存分配次数

2.3.8 request_pool_size

语法: request_pool_size size;
默认:request_pool_size 4k;
配置块: http、server

  • Nginx开始处理HTTP 请求时,将会为每个请求都分配一个内存池,size 配置项将指定这个内存池的初始大小(即ngx_http_request_t 结构体中的pool内存池初始大小),用于减少内核对于小块内存的分配次数。TCP 连接关闭时会销毁 connection pool size 指定的连接内存池,HTTP 请求结束时会销request pool size指定的HTTP请求内存池,但它们的创建、销毁时间并不一致,因为一个 TCP 连接可能被复用于多个 HTTP 请求。

2.4 网络连接的设置

2.4.1 读取HTTP头部的超时时间

语法:client_header_timeout_time (默认单位:秒)
默认: client_header_timeout 60;
配置块: http、server、location

  • 客户端与服务器建立连接后将开始接收 HTTP 头部,在这个过程中,如果在一个时间间隔(超时时间)内没有读取到客户端发来的字节,则认为超时,并向客户端返回 408("Request timed out")响应

2.4.2 读取HTTP包体的超时时间

语法: client_body_timeout time(默认单位:秒);
默认: client_body_timeout 60;
配置块: http、server、location

  • 此配置项与client header timeout 相似,只是这个超时时间只在读取HTTP 包体时才有效

2.4.3 发送响应的超时时间

语法: send_timeout time;
默认: send_timeout 60;
配置块: http、server、location

  • 这个超时时间是发送响应的超时时间,即Nginx 服务器向客户端发送了数据包,但客户端一直没有去接收这个数据包。如果某个连接超过 send timeout 定义的超时时间,那么Nginx 将会关闭这个连接。

2.4.4 reset_timeout_connection

语法: reset_timeout_connection on|off;
默认: reset_timeout_connection off;
配置块: http、server、location

  • 连接超时后将通过向客户端发送RST 包来直接重置连接。这个选项打开后,Nginx 会在某个连接超时后,不是使用正常情形下的四次握手关闭TCP 连接,而是直接向用户发送 RST 重置包,不再等待用户的应答,直接释放 Nginx 服务器上关于这个套接字使用的所有缓存(如TCP 滑动窗口)。相比正常的关闭方式,它使得服务器避免产生许多处于 FIN_WAIT1、FIN_WAIT2、TIME_WAIT 状态的TCP 连接。
    注意,使用 RST 重置包关闭连接会带来一些问题,默认情况下不会开启。

2.4.5 lingering_close

语法: lingering_close off|on always;
默认: lingering_close on;
配置块: http、server、location

  • 该配置控制 Nginx 关闭用户连接的方式。
    • always 表示关闭用户连接前必须无条件地处理连接上所有用户发送的数据。
    • off 表示关闭连接时完全不管连接上是否已经有准备就绪的来自用户的数据。
    • on是中间值,一般情况下在关闭连接前都会处理连接上的用户发送的数据,除了有些情况下在业务上认定这之后的数据是不必要的。

2.4.6 lingering_time

语法: lingering_time time;
默认: lingering time 30s;
配置块: http、server、location

  • lingering_close 启用后,这个配置项对于上传大文件很有用。上文讲过,当用户请求的Content-Length 大于max client body size 配置时,Nginx 服务会立刻向用户发送413(Requestentity too large)响应。但是,很多客户端可能不管 413 返回值,仍然持续不断地上传 HTTP body,这时,经过了lingering time 设置的时间后,nginx 将不管用户是否仍在上传,都会把连接关闭掉。

2.4.7 lingering_timeout

语法: lingering_timeout time;
默认: lingering_timeout 5s;
配置块: http、server、location

  • lingering_close生效后,在关闭连接前,会检测是否有用户发送的数据到达服务器,如果超过 lingering_timeout 时间后还没有数据可读,就直接关闭连接,否则,必须在读取连接缓冲区上的数据并丢弃掉后才会关闭连接。

2.4.8 对某些浏览器禁用 keepalive 功能

语法: keepalive_disable [ msie6 | safari | none ] ...
默认: keepalive_disable msie6 safari
配置块: http、server、location

  • HTTP 请求中的 keepalive 能是为了让多个请求复用一个HTTP 长连接,这个功能务器的性能提高是很有帮助的。但有些浏览器,如 IE6和 Safari,它们对于使用 keepalive 功能的POST请求处理有功能性问题。因此,针对IE 6及其早期版本、Safari 浏览器默认用 keepalive 功能的。

2.4.9 keepalive 超时时间

语法:keepalive_timeout time (默认单位:秒);

默认: keepalive_timeout 75;

配置块: http、server、location

  • 一个 keepalive 连接在闲置超过一定时间后(默认的是75秒),服务器和浏览器都会去关闭这个连接。当然,keepalive timeout 配置项是用来约束 Nginx 服务器的,Nginx也会按照规范把这个时间传给浏览器,但每个浏览器对待 keepalive 的策略有可能是不同的。

2.4.10 一个 keepalive 长连接上允许承载的请求最大数

语法: keepalive_requests n;
默认: keepalive_requests 100;
配置块: http、server、location

一个 keepalive 连接上默认最多只能发送100个请求

2.4.11 tcp_nodelay

语法: tcp_nodelay on | off;

默认: tcp_nodelay on;

配置块: http、server、location

  • 确定对 keepalive 连接是否使用TCP_NODELAY 选项

2.4.12 tcp_nopush

语法:tcp_nopush on|off;

默认: tcp_nopush off;

配置块: http、server、location

  • 在打开sendfile选项时,确定是否开启FreeBSD系统上的TCP_NOPUSH或Linux系统上的TCP_CORK功能。打开 tcp_ nopush 后,将会在发送响应时把整个响应包头放到一个TCP包中发送。

2.5 MIME类型的设置

2.5.1 MIMEtype与文件扩展的映射

语法: type {...};
配置块; http、server、location

  • 定义MIME type 到文件扩展名的映射。多个扩展名可以映射到同一个MIME type。例如
    types {
      text/html	html;
      text/html	conf;
      image/gif	gif;
      image/jpeg jpg;  
    }
    
    

2.5.2 默认MIME type

语法: default_type MIME-type;
默认: default_type text/plain;
配置块: http、server、location

  • 当找不到相应的MIME type 与文件扩展名之间的映射时,使用默认的MIME type作为HTTP header中的 Content-Type

2.5.3 types_hash_bucket_size

语法: types_hash_bucket_size size;
默认: types_hash_bucket_size 32 | 64 | 128
配置块: http、server、location

  • 为了快速寻找到相应MIME type,Nginx使用散列表来存储MIME type 与文件扩展名 types_hash_bucket_size 设置了每个散列桶占用的内存大小。

2.5.4 types_hash_max_size

语法: types_hash_max_size size;
默认: types_hash_max_size 1024:
配置块: http、server、locationtypes hash max size

  • 影响散列表的冲突率。types_hash_max_size越大,就会消耗更多的内存,但散列 key的冲突率会降低,检索速度就更快。types hash max size 越小,消耗的内存就越小,但散列 key 的冲突率可能上升。