``` listen unix:/var/run/nginx.sock; listen 127.0.0.1:8000; listen 127.0.0.1; listen 8000; listen *:8000; listen localhost:8000 bind; listen [::]:8000 ipv6only=on; listen [::1] ``` # 11个阶段之前的处理 处理`HTTP`请求头部。 ``` --操作系统内核 三次握手,SYN, SYN-ACK, ACK Nginx选择自己的worker --事件模块 worker进程通过epoll_wait方法返回获取刚才建立连接的句柄 拿到建立连接的句柄,是一个读事件 调用accept方法,分配连接内存池,内存池包括连接内存池和请求内存池(connection_pool_size:512) --HTTP模块 通过一个回调方法,把读事件通过epoll_ctl函数添加到epoll的事件队列中,并且添加超时定时器(client_header_timeout:60s) ``` 当客户端再次发送请求,操作系统读取报文,把请求交给`Nginx`的`HTTP`模块,把内核中的DATA读取到用户态的内存(大小通过`client_header_bufer_size`:`1k`)中。具体如下: ``` --分配请求内存池:request_pool_size:4k --状态机解析请求行 --分配大内存:large_client_header_buffers 4 8k;最多32k --状态机解析请求行 --标识URI --状态机解析header --分配大内存large_client_header_buffers:4 8k --标识header --移除超时定时器:client_header_timeout:60s --开始11个阶段的http请求处理 ``` # 正则表达式 正则表达式--元字符 ``` . 换行符以外的任意 \w \s 空白 \d \b 单词 ^ 字符串开始 $ 字符串结束 ``` 正则表达式--重复 ``` * 零或更多 + 一次或更多 ? 零次或一次 {n}重复n次 {n,}n次或更多 {n,m}n到m次 ``` 正则表达式,例子 ``` 原始:/admin/website/article/35/change/uploads/party/5.jpg 编写正则表达式:/^\/admin\/website\/article\/(\d+)\/change\/uploads\/(\w+)\/(\w+)\.(png|jpg|gif|jpeg|bmp)$/ 使用工具:pcretest 输入正则标识 观察结果 ``` # 处理请求,使用哪一个`server` ``` --跟多个域名 server_name example.com www.example.com --泛域名 server_name *.example.com --正则表达式 server_name ~^www\.d+\.example\.com$; ``` `server_name_in_redirect`的使用 ``` --配置文件 server { server_name primary.example.com second.example.com; server_name_in_redirect on; return 302 /redirect; } --请求:curl second.exmaple.com -I Location:http://primary.example.com/redirect ``` 使用正则表达式创建变量 ``` server { server_name ~^(www\.)?(.+)$; location / {root /sites/$2;} } server { server_name ~^(www\.)?(?.+)$; location / {root/sites/$domain;} } ``` 另外 ``` .example.com 匹配example.com *.example.com _匹配所有域名 ""匹配没有传递Host头部的情况 ``` # 请求的11个阶段 ``` --POST_READ:处理请求头之后,realip模块处理 --SEVER_REWRITE:rewrite模块 --FIND_CONFIG: --REWRITE:rewrite模块 --POST_REWRITE --PRE_ACCESS:使用limit_conn, limit_req模块 --ACCESS:使用auth_basic, access, auth_request模块 --POST_ACCESS --PRECONTENT:使用try_files模块 --CONTENT:使用index, autoindex, concat模块 --LOG:使用access_log模块 ``` # 11个阶段顺序处理 ``` --postread realip模块 rewrite模块 find_config模块 rewrite模块 --preaccess limit_req模块 limit_conn模块 --access access模块 auth_basic模块 auth_request模块 --precontent tyr_files模块 mirrorsMok --content concat模块 random_index模块 index模块 auto_index模块 static模块 --log ``` # `postread`阶段的`realip`模块 ``` server { server_name realip.example.com; error_log logs/myerror.log debug; set_real_ip_from xx.xx.xx.xx; real_ip_recursive off; real_ip_header X-Forwarded-For; location / { return 200 "Client real ip: $remote_addr\n"; } } --请求:curl -H 'X-Forwared-For:1.1.1.1,xx.xx.xx.xx' realip.example.com ``` # `postread`阶段的`rewrite`模块 ``` --postread realip模块 rewrite模块 find_config模块 rewrite模块 ``` 如果`rewrite`模块中`return`,就不会往下执行了。 `return`指令 ``` 444:关闭连接 301:永久重定向 302:临时重定向 303: 临时重定向,允许改变方法,禁止被缓存 307: 临时重定向,允许改变方法,禁止被缓存 308: 永久重定向,不允许改变方法 ``` `error_page`指令 ``` error_page 404 /404.html; error_page 500 502 503 504 /50x.html; error_page 404=200 /empty.gif; error_page 404=/404.php; location / { error_page 404=@fallback; } location @fallback { proxy_pass http:backend; } error_page 403 http://example.com/s.html; error_page 404=201 http://example.com/b.html; ``` 例子 ``` server { server_name www.example.com; listen 8080; root html/; error_page 404 /403.html; location / { return 404 "find nothing"; } } 返回"find nothing" server { server_name www.example.com; listen 8080; root html/; error_page 404 /403.html; return 405; location / { return 404 "find nothing"; } } 返回"405" ``` `rewrite`指令,用来替换`url`。 ``` rewrite regex replacement[flag]; --当replacement以http://, https://, $schema开头,返回302 --flag指定方式 --last: 把replacement作为新的url与location匹配 --break:停止当前脚本执行 --redirect:302重定向 --perment:301重定向 ``` `rewrite`指令例子 ``` root html/; locatioin /first { rewrite /first(.*)/second$1 last; return 200 'first'; } ``` `rewrite`指令中的`if`指令 ``` if($http_user_agen~MSIE) { rewrite ^(.*)$/msie/$1 break; } ``` # `postread`阶段的`find_config` `location`指令 ``` = 精确匹配 ^~匹配上后则不再进行正则表达式匹配 ~大小写敏感正则匹配 ~*大小写不敏感正则匹配 ``` # `preaccess`阶段限制并发连接数 ``` limit_conn_zone $binary_remote_addr zone=addr:10m; server { server_name www.example.com; root html/; error_log myerror.log info; location / { limit_conn_status 500; limit_conn_log_level warn; limit_rate 50;//每秒50次 limit_conn addr 1; //1个字节 } } ``` # `preaccess`限制每秒处理请求数 ``` limit_req_zone $binary_remote_addr zone=one:10m rate=2/m; server { server_name www.example.com; root html/; error_log myerror.log info; location / { limit_conn_status 500; limit_conn_log_level warn; limit_req zone=one; #limit_req zone=one burst=3 nodelay; } } ``` # `access`阶段对`ip`做限制 `access`模块。 ``` location / { deny 192.168.8.1; allow ...; } ``` # `access`阶段对用户名密码做限制 `auth_basic`模块。使用了`RFC2617`协议中的`HTTP Basic Authentication`。本身用明文,但用了`HTTPS`以后加密。 ``` ``` # `access`阶段使用第三方做权限控制 `auth_request`模块。 # `access`阶段的`satisfy`指令 # `precontent`阶段按序访问资源 `try_files`模块。 # `precontent`阶段实时拷贝流量 `mirror`模块。 # `content`阶段`root`和`alias`指令 # `static`模块 # `index`和`autoindex`模块 # 提升多个小文件性能的`concat`模块 # 过滤模块 # `Nginx`变量 # 提升连接效率 `keepalive`