nginx教程第五篇:用HTTP核心模块配置一个静态Web服务器(一)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013068377/article/details/82821659

前言

静态Web服务器的主要功能由ngx_http_core_module模块( HTTP框架的主要成员) 实现,
当然, 一个完整的静态Web服务器还有许多功能是由其他的HTTP模块实现的。 本文主要讨
论如何配置一个包含基本功能的静态Web服务器, 文中会完整地说明ngx_http_core_module模
块提供的配置项及变量的用法, 但不会过多说明其他HTTP模块的配置项。 在阅读完本节内
容后, 读者应当可以通过简单的查询相关模块( 如ngx_http_gzip_filter_module、
ngx_http_image_filter_module等) 的配置项说明, 方便地在nginx.conf配置文件中加入新的配置
项, 从而实现更多的Web服务器功能。
除了上文提到的基本配置项外, 一个典型的静态Web服务器还会包含多个server块和
location块, 例如:

http {
    gzip on;
    upstream {
        …
    }
    … 
    server {
        listen localhost:80;
        … 
        location /webstatic {
            if …
            {
                …
            }
            root optwebresource;
            …
        }
        location ~* .(jpg|jpeg|png|jpe|gif)$ {
            …
        }
    }
    server {
        …
    }
}

说明:

  1. 所有的HTTP配置项都必须直属于http块、 server块、 location块、 upstream块或if块等( HTTP配置项自然必须全部在http{}块之内, 这里的“直属于”是指配置项直接所属的大括号
    对应的配置块),同时,在描述每个配置项的功能时, 会说明它可以在上述的哪个块中存在,因为有些配置项可以任意地出现在某一个块中, 而有些配置项只能出现在特定的块中。
  2. Nginx为配置一个完整的静态Web服务器提供了非常多的功能, 下面会把这些配置项分为以下8类进行详述:

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

这种划分只是为了帮助大家从功能上理解这些配置项。在这之后会列出ngx_http_core_module模块提供的变量, 以及简单说明它们的意义。

虚拟主机与请求的分发

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

1. 监听端口
语法: listen address:port [default(deprecated in 0.8.21)|
    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;
listen 127.0.0.1; #注意: 不加端口时, 默认监听80端口
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;

下面说明listen可用参数的意义。

·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. 主机名称
语法: 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域名的请求提供不同的服务,
以此实现虚拟主机功能。

3. server_names_hash_bucket_size
语法: 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设置了每个散列桶占用的内存大小。

4. server_names_hash_max_size
语法: 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的冲突率可能增高。
5. 重定向主机名称的处理
语法: server_name_in_redirect on|off;
默认: server_name_in_redirect on;
配置块: http、 server或者location

该配置需要配合server_name使用。 在使用on打开时, 表示在重定向请求时会使用
server_name里配置的第一个主机名代替原先请求中的Host头部, 而使用off关闭时, 表示在重
定向请求时使用请求本身的Host头部。
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 / {
    # /可以匹配所有请求
    …
}

文件路径的定义

1. 以root方式设置资源路径
语法: root path;
默认: root html;
配置块: http、 server、 location、 if
例如, 定义资源文件相对于HTTP请求的根目录。
location /download/ {
	root optwebhtml;
}
在上面的配置中, 如果有一个请求的URI是/download/index/test.html, 那么Web服务器将
会返回服务器上 optwebhtml/download/index/test.html 文件的内容。
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则不 然, 它会根据完整的URI请求来映射, 因此, /conf/nginx.conf请求会根据root path映射为 path/conf/nginx.conf。 这也是root可以放置到http、 server、 location或if块中, 而alias只能放置 到location块中的原因。 alias后面还可以添加正则表达式, 例如: ``` location ~ ^/test/(\w+)\.(\w+)$ { alias usr/local/nginx/$2/$1.$2; } ``` 这样, 请求在访问/test/nginx.conf时, Nginx会返回 usr/local/nginx/conf/nginx.conf文件中的 内容。
3. 访问首页
语法: index file...;
默认: index index.html;
配置块: http、 server、 location

有时, 访问站点时的URI是/, 这时一般是返回网站的首页, 而这与root和alias都不同。
这里用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文件的内容, 依此类推。
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 上游服务器中处理。

5. 是否允许递归使用error_page
语法: recursive_error_pages [on|off];
默认: recursive_error_pages off;
配置块: http、 server、 location

确定是否允许递归地定义error_page
6. try_files
语法: try_files path1[path2] uri;
配置块: server、 location

try_files后要跟若干路径, 如path1 path2…, 而且最后必须要有uri参数, 意义如下: 尝试
按照顺序访问每一个path, 如果可以有效地读取, 就直接向用户返回这个path对应的文件结
束请求, 否则继续向下访问。 如果所有的path都找不到有效的文件, 就重定向到最后的参数
uri上。 因此, 最后这个参数uri必须存在, 而且它应该是可以有效重定向的。 例如:

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

上面这段代码表示如果前面的路径, 如systemmaintenance.html等, 都找不到, 就会反向
代理到http://backend 服务上。 还可以用指定错误码的方式与error_page配合使用, 例如:

location {
	try_files $uri $uri /error.phpc=404 =404;
}

内存及磁盘资源的分配

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. 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设置的值, 包体还是会写入到磁盘文件中。

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将会生效

4. 存储超大HTTP头部的内存buffer大小
语法: large_client_header_buffers number size;
默认: large_client_header_buffers 48k;
配置块: 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大小。

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, 以降低内存消耗

6. HTTP包体的临时存放目录
语法: client_body_temp_path dir-path[level1[level2[level3]]]
默认: 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 optnginx/client_temp 1 2;
如果新上传的HTTP包体使用00000123456作为临时文件名, 就会被存放在这个目录中。
optnginx/client_temp/6/45/00000123456

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

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

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请求。

紧接后续文章:nginx教程第六篇:用HTTP核心模块配置一个静态Web服务器(二)

猜你喜欢

转载自blog.csdn.net/u013068377/article/details/82821659