nginx 学习3-http模块1

297 阅读17分钟

1. http 配置


main
http {
    upstream { … }
    split_clients {…}
    map {…}
    geo {…}
    server {
        if () {…}
        location {
            limit_except {…}
        }
        location {
            location {
            }
        }
        }
    server {
    }
}

指令合并

值指令: 存储配置项的值 (可以合并)

  • root
  • access_log
  • gzip

动作类指令: 指定行为 (不可以合并)

  • rewrite
  • proxy_pass 生效阶段
  • server_rewrite 阶段
  • rewrite 阶段
  • content 阶段

存储值的指令继承规则: 向上覆盖

  • 子配置不存在时,直接使用父配置块
  • 子配置存在时,直接覆盖父配置块

例子

server { 
    listen 8080;
    root /home/geek/nginx/html;
    access_log logs/geek.access.log main;
    location /test {
        root /home/geek/nginx/test; # 这里会覆盖上面的
        access_log logs/access.test.log main; # 这里会覆盖上面的
    }
    location /dlib {
        alias dlib/;
    }
    location / {

    }
}

HTTP 模块合并配置的实现

char *(*merge srv conf)(ngx conf t*cf, void *prev, void *conf); # 在 server 块内生效,从 http 向 server 合并指
char *(*merge loc conf)(ngx conf t *cf, void *prev, void *conf); # 配置缓存在内存

2.listen指令

Default: listen *:80 | *:8000;

例子

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];

3.处理HTTP请求头部的流程

接收请求事件模块

操作系统内核 worker线程 -> 事件模块 (epoll wait 分配连接池) -> http模块 (设置回调方法与超时定时器)

->data ack 数据包 -> epoll wait -> 分配内存与 读写缓存区

image.png

接收请求 HTTP 模块

接收URI

  1. 分配请求内存池 request pool size:4k
  2. 状态机解析请求行
  3. 分配大内存 large client header buffers:4 8k
  4. 状态机解析请求行
  5. 标识URI

接收header

  1. 状态机解析header
  2. 分配大内存 large client header buffers:4 8k
  3. 标识header
  4. 移除超时定时器 client header timeout: 60s
  5. 开始11个阶段的http请求处理

请求限制

client_header_buffer_size 10m;  
large_client_header_buffers 4 16k; # number size; 读取大型客户端请求头的缓冲区的最大数量和大小

4.正则表达式

元字符

. # 匹配除换行符以外的任意字符
\w # 匹配字母或数字或下划线或汉字
\s # 匹配任意的空白符
\d # 匹配数字
\b # 匹配单词的开始或结束
^ # 匹配字符串的开始 
$ # 匹配字符串的结束

重复

* # 重复零次或更多次
+ # 重复一次或更多次 
? # 重复零次或一次
{n} # 重复n次
{n,} # 重复n次或更多次n1
{n,m} # 重复n到m次

## 转义与分组
\ # 转义符号: 取消元字符的特殊含义
() # 分组与取值

# 范围
[] :定义匹配的字符范围
[c] :匹配单个字符 c
注意:在括号里面用-表示范围:
[a-z] :匹配 a-z 小写字母的任意一个
[a-zA-Z0-9] :匹配所有大小写字母或数字
() :表达式的开始和结束位置 例如:(jpg|gif|swf|)

安装

# 下载 pcretest
https://www.pcre.org/
# 
tar -xzvf  pcre2-10.42.tar.gz

# 进入该目录,运行configure
cd pcre2-10.42
./configure --enable-utf8  
# 执行make命令
make && make install
# 使用pcre2test命令
pcre2test 
# 输入正则
re> /^\/admin\/website\/article\/(\d+)\/change\/uploads\/(\w+)\/(\w+)\.(png|jpg|gif|jpeg|bmp)$/
# 输入验证的数据
data> /admin/website/article/35/change/uploads/party/5.jpg
# 输出结果
#  0: /admin/website/article/35/change/uploads/party/5.jpg
#  1: 35
#  2: party
#  3: 5
#  4: jpg

# 测试例子2 nginx中 url替换
# 原始
/admin/website/article/35/change/uploads/party/5.jpg
# 转化后 
/static/uploads/party/5.jpg

#使用的正则 
/^\/admin\/website\/article\/(\d+)\/change\/uploads\/(\w+)\/(\w+)\.(png|jpg|gif|jpeg|bmp)$/

# 通过rewrite重写 
rewrite /^\/admin\/website\/article\/(\d+)\/change\/uploads\/(\w+)\/(\w+)\.(png|jpg|gif|jpeg|bmp)$
 /static/uploads/$2/$3.$4 last;
# 

5.server_name 指令

## 指令后可以跟多个域名,第1个是主域名
server_name_in_redirect on / off # 默认 off
Context: http, server, location

## 泛域名:仅支持在最前或者最后 
server_name *test.com

## 正则表达式:加~前缀
server_name www.test.com ~^www\d+\.test\.com$

例子 用正则创建变量


server {
    server_name ~^(www\.)?(.+)$;
    location / { 
        root /sites/$2; 
    }
}
server {
    server_name ~^(www\.)?(?<domain>.+)$;
    location / {
         root /sites/$domain;
    }
}

# 其他匹配
.test.com 可以匹配  test.com*  .test.com
_ 匹配所有
"" 匹配没有Host头部

例子

server {
    server_name primary.test.com second.test.com; # 第一个为主域名
    server_name_in_redirect on;
    return 302 /redirect;
}

# 测试命令 
curl second.test.com -I
# 当 server_name_in_redirect为 on  会重定向到主域名 
# 输出
Location: http://primary.test.com/redirect

# 当 server_name_in_redirect为 off 还是当前请求的域名
Location: http://second.test.com/redirect

Server 匹配顺序

  1. 精确匹配
  2. *在前的泛域名
  3. *在后的泛域名
  4. 按文件中的顺序匹配正则表达式域名
  5. default server : 第一个 ,listen 指定 default

6. 11个阶段的顺序处理

  1. postread 阶段 realip
  2. server_rewrite 阶段 rewrite
  3. find_config 阶段
  4. rewrite 阶段 rewrite
  5. post_rewrite 阶段
  6. preaccess 阶段 limit_req limit_conn
  7. access 阶段 access autn_basic autn_request
  8. postaccess 阶段
  9. precontent 阶段 try_files
  10. content 阶段 concat index auto_index
  11. log阶段 access_log

关键的6个阶段

1.postread - post_rewrite 阶段

  • realip
  • server_rewrite
  • find_config
  • rewrite

2.preaccess 阶段

  • limit_req
  • limit_conn

3.access 阶段

  • access
  • autn_basic
  • autn_request

4.precontent 阶段

  • try_files
  • mirrors

5.content 阶段

  • concat
  • random_index
  • index
  • auto_index
  • static

6.log 阶段

  • log

11个阶段源码对照

char *ngx_module_names[] = {
    "ngx_http_static_module",
    "ngx_http_autoindex_module",
    "ngx_http_index_module",
    "ngx_http_random_index_module",
    "ngx_http_mirror_module",
    "ngx_http_try_files_module",
    "ngx_http_auth_request_module",
    "ngx_http_auth_basic_module",
    "ngx_http_access_module",
    "ngx_http_limit_conn_module",
    "ngx_http_limit_req_module",
    "ngx_http_realip_module",
    "ngx_http_referer_module",
    "ngx_http_rewrite_module",
    "ngx_http_concat_module",
}

7.realip

拿到真实的用户 IP 地址

前提

  1. TCP 连接四元组 (src ip,src port, dst ip,dst port) 源码ip和端口, 目标ip和端口
  2. HTTP头部X-Forwarded-For 用于传递IP
  3. HTTP头部X-Real-IP 用于传递用户IP
  4. 网络中存在许多反向代理

完整流程 例子


用户        -> ADSL         -> CDN      -> 某个方向代理 -> Nginx

192.168.0.x -> 115.204.33.1 -> 1.1.1.1  -> 2.2.2.2     -> Nginx 通过 X-Real-IP拿到 115.204.33.1

用户
内网IP:192.168.0.x

ADSL
运营商公网IP:115.204.33.1  # 这个才是用户真正的ip

CDN
IP地址: 1.1.1.1
X-Forwarded-For: 115.204.33.1
X-Real-IP: 115.204.33.1

某个方向代理
IP地址: 2.2.2.2
X-Forwarded-For: 115.204.33.1 , 1.1.1.1
X-Real-IP: 115.204.33.1

Nginx
用户地址: 115.204.33.1
remote_addr变量:2.2.2.2

通过 binary_remote_addr& remote_addr 拿到用户的真实ip, 再结合limit conn模块实现限制。

realip 模块

默认不会编译进Nginx ,编译 --with-http-realip 启用功能

指令

  • set_real_ip_from
  • real_ip_header
  • real_ip_recursive

变量

  • realip_remote_addr
  • realip_remote_port

例子

# 编译
./configure --with-http_realip_module

server {
    server_name localhost; 
    error_log logs/myerror.log debug;
    set_real_ip_from  116.62.160.193; #  将会被替代为精确的IP地址。 
    #real_ip_header X-Real-IP;  # 客户端真实的 IP
    #real_ip_recursive off;  # 是否递归解析,off表示默认从最后一个地址开始解析; 
    real_ip_recursive on; # on表示从前往后依次递归获取ip
    real_ip_header X-Forwarded-For; # 设置使用哪个头来替换IP地址。该模块将会使用X-Forwarded-For头中的最后一个IP地址来替换前端代理的IP地址。

    location /{
        return 200 "Client real ip: $remote_addr\n";
    }
}


# 测试命令 
curl -H 'X-Forwarded-For:1.1.1.1,172.25.70.1' localhost:8890 
# 设置real_ip_recursive on  X-Forwarded-For显示 172.25.70.1
#Client real ip: 1.1.1.1

# 设置real_ip_recursive off X-Forwarded-For 显示 1.1.1.1 
#Client real ip: 172.25.70.1

8.rewrite 模块

return 指令

返回状态码

1. Nginx自定义 :

  • 444:关闭连接

2. HTTP 1.0标准

  • 301: http1.0永久重定向
  • 302:临时重定向,禁止被缓存

3. HTTP1.1标准

  • 303:临时重定向,允许改变方法,禁止被缓存
  • 307:临时重定向,不允许改变方法,禁止被缓存
  • 308:永久重定向,不允许改变方法

server与location块下的return指令关系

优先执行server的return

server {
    server_name localhost;
    listen 8080;
    root html/;
    error_page 404 /403.html; 
    return 403;
    location /{
        return 404 "find nothing!";
    }
}

curl localhost:8080/aaa.txt
# 默认优先输出 server上定义的 403 

# 当注释  # return 403; 
显示 find nothing! 

return与error_page

error写法

1. error_page 404 /404.html;
2. error_page 500 502 503 504 /50x.html;
3. error_page 404 =200 /empty.gif;
4. error_page 404 = /404.php;
5.  location / {
        error_page 404 = @fallback;
    }
        location @fallback {
        proxy_pass http://backend;
    }
6. error_page 403 http://example.com/forbidden.html;
7. error_page 404 =301 http://example.com/notfound.html;

rewrite指令

Syntax: rewrite regex replacement [flag];

Context: server. location,if

功能

  1. 将regex指定的url替换成replacement这个新的url
  • 可以使用正则表达式及变量提取
  1. 当replacement以http://或者https://或者Sschema开头,则直接返回302重定向替换后的url根据flag指定的方式进行处理
  • --last:用replacement这个URI进行新的location匹配-break: break指令停止当前脚本指令的执行,等价于独立的break指令
  • --redirect: 返回302重定向
  • --permanent: 返回301重定向

例子

# 目录结构
html/first/
└── 1.txt
html/second/
└── 2.txt
html/third/
└── 3.txt

# conf配置
server {
    listen 8891;
	server_name localhost;
	rewrite_log on; #默认关闭
	error_log logs/rewrite_error.log notice; # 默认会把 重定向写入 到 error里面

	root html/;
	location /first {
		rewrite /first(.*) /second$1 last; #当访问 /first/3.txt时候 (.*) 匹配 /3.txt  即重定向到  /second/3.txt
		return 200 'first!\n';
	}

	location /second {
		rewrite /second(.*) /third$1 break; # 当访问 /second/3.txt时候 (.*) 匹配 /3.txt,  即重定向到  /third/3.txt
		#rewrite /second(.*) /third$1;
		return 200 'second!\n';
	}

	location /third {        # 当访问 /third/3.txt时候,  由于该路径确实存在,返回 内容333 , 不返回 third!
		return 200 'third!\n';
	}

	location /redirect1 {
		rewrite /redirect1(.*) $1 permanent; # 返回301 重定向到 / 
	}

	location /redirect2 {
		rewrite /redirect2(.*) $1 redirect;  # 返回302  重定向到 / 
	}

	location /redirect3 {
             rewrite /redirect3(.*) http://localhost$1; # 不写 默认还是 302 ,重定向到 http://localhost
        }

	location /redirect4 {
            rewrite /redirect4(.*) http://localhost$1 permanent; # 不写 默认还是 301 ,重定向到 http://localhost
        }
}

# 测试wriite访问
curl localhost:8891/first/3.txt
# 返回 333
 
# 测试redirect 访问
curl localhost:8891/redirect1/ -I # 返回 301
curl localhost:8891/redirect2/ -I # 返回 302
curl localhost:8891/redirect3/ -I # 返回 302
curl localhost:8891/redirect4/ -I # 返回 301

# 日志输出内容 一次请求,一次重定向
2023/03/15 10:38:53 [notice] 56760#0: *44 "/redirect1(.*)" matches "/redirect1/", client: 127.0.0.1, server: localhost, request: "HEAD /redirect1/ HTTP/1.1", host: "localhost:8891"
2023/03/15 10:38:53 [notice] 56760#0: *44 rewritten redirect: "/", client: 127.0.0.1, server: localhost, request: "HEAD /redirect1/ HTTP/1.1", host: "localhost:8891"

条件判断 if

context: server , location

规则: 条件为真执行{}里面内容, 指令可以继承

if 指令的条件表达式

1. 检查变量为空或者值是否为0,直接使用
2. 将变量与字符串做匹配,使用 = 或者 !=
3. 将变量与正则表达式做匹配
大小写敏感,~或者!~
大小写不敏感,~*或者!~*
4. 检查文件是否存在,使用-f 或者 !-f
5. 检查目录是否存在,使用-d或者!-d
6. 检查文件、目录、软链接是否存在,使用-e或者!-e
7. 检查是否为可执行文件,使用-x或者!-x

例子

if ($http_user_agent ~ MSIE) {
    rewrite ^(.*)$ /msie/$1 break;
}
if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
    set $id $1;
}
if ($request_method = POST) {
    return 405;
}
if ($slow) {
    limit_rate 10k;
}
if ($invalid_referer) {
    return 403;
}

9.find_config

location

只匹配URI 不匹配参数

location[=|~|~*|^~] uri { ... }
location @name { ...}
Context:server,location

merge_slashes on/off # 默认 on 合并连续的/符号
Context:http, server

分类

  1. 常规
  • =:精确匹配
  • ^~:匹配上后则不再进行正则表达式匹配
  1. 正则表达式
  • ~ :大小写敏感
  • ~* :忽略大小写
  1. @ : 用于内部跳转的命名location

location 匹配逻辑

依次优先顺序

  1. location =
  2. location 完整路径 (最长路径优先)
  3. location ^~ 否定正则
  4. location ~* 正则顺序,不区分大小写
  5. location ~ 区分大小写正则顺序
  6. location 部分起始路径
  7. /

例子

   #1.  = : 用于不包含正则表达式的uri前,必须与指定的模式精确匹配(区分大小写,并且后面带/是有区别的)
   location = /bbb {
        default_type text/plain;
        return 200 "access success bbb \n\r";
   } 
    # 能匹配到:
    http://127.0.0.1:8081/bbb
    http://127.0.0.1:8081/bbb?p1=TOM
    # 不能匹配到(大小写区分):
    http://127.0.0.1:8081/bbb/
    http://127.0.0.1:8081/bbbcd
    http://127.0.0.1:8081/Bbb


   #2.location /完整路径
    location /aaa/bbb/ccc/ddd {
        default_type text/plain;
        return 200 "access success aaa \n\r";
   }
     # 只能匹配到:
    http://127.0.0.1:8081//aaa/bbb/ccc/ddd  


  #3.  ^~: 用于不包含正则表达式的uri前,功能和不加符号的一致,唯一不同的是,如果模式匹配,那么就停止搜索其他模式了,可用于提升优先级。(区分大小写,并且后面带/是有区别的)
   location ^~ /fff {
        default_type text/plain;
        return 200 "access success. Non Regular expression matched: fff  \n\r";
   }
    # 能匹配到:
    http://127.0.0.1:8081/fff
    http://127.0.0.1:8081/fff/
    http://127.0.0.1:8081/fffdef
    http://127.0.0.1:8081/fff/def/
    http://127.0.0.1:8081/fff?p1=TOM
    # 不能匹配到(大小写区分):
    http://127.0.0.1:8081/Fff
    http://127.0.0.1:8081/pp/fff
    # 如果规则(后面跟/目录符号) location /fff/ { 则只能匹配到下面两行:
    http://127.0.0.1:8081/fff/
    http://127.0.0.1:8081/fff/def/


   
   #4.  ~*: 用于表示当前uri中包含了正则表达式,并且不区分大小写
   # 正则表达式:不区分大小写,以/abc开头,以字母或数字或下划线或汉字结束的
   location ~*^/ddd\w$ {
        default_type text/plain;
        return 200 "access success. 111 Regular expression matched: ddd  \n\r";
   }
    # 能匹配到:
    http://127.0.0.1:8081/dddb
    http://127.0.0.1:8081/dddB
    http://127.0.0.1:8081/ddd2
    http://127.0.0.1:8081/DddH
    # 不能匹配到(大小写区分):
    http://127.0.0.1:8081/ddd
    http://127.0.0.1:8081/Ddd
    http://127.0.0.1:8081/ddd/
    http://127.0.0.1:8081/ddddef
    http://127.0.0.1:8081/ddd/def/
    http://127.0.0.1:8081/ddd?p1=TOM

   
   #5.  ~ : 用于表示当前uri中包含了正则表达式,并且区分大小写
   # 正则表达式:区分大小写,以/abc开头,以1个字母或数字或下划线或汉字结束的
   location ~^/eee\w$ {
        default_type text/plain;
        return 200 "access success. 000 Regular expression matched: eee  \n\r";
   }
    # 能匹配到:
    http://127.0.0.1:8081/eeeb
    http://127.0.0.1:8081/eeeB
    http://127.0.0.1:8081/eee2
    # 不能匹配到(大小写区分):
    http://127.0.0.1:8081/eee
    http://127.0.0.1:8081/Eee
    http://127.0.0.1:8081/eee/
    http://127.0.0.1:8081/eeedef
    http://127.0.0.1:8081/eee/def/
    http://127.0.0.1:8081/eee?p1=TOM
 

    #6.  不带符号,要求必须以指定模式开始(区分大小写,并且后面带/是有区别的)
    location /aaa/ {
        default_type text/plain;
        return 200 "access success aaa \n\r";
   } 
    # 能匹配到:
    http://127.0.0.1:8081/aaa
    http://127.0.0.1:8081/aaa/
    http://127.0.0.1:8081/aaadef
    http://127.0.0.1:8081/aaa/def/
    http://127.0.0.1:8081/aaa?p1=TOM
    # 不能匹配到(大小写区分):
    http://127.0.0.1:8081/Aaa
    # 如果规则(后面跟/目录符号) location /aaa/ { 则只能匹配到下面两行:
    http://127.0.0.1:8081/aaa/
    http://127.0.0.1:8081/aaa/def/

   #7.   /  
   # 因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求
   # 但是正则和最长字符串会优先匹配 
    location / {
         default_type text/plain;
        return 200 "access success root \n\r";
    }

测试例子2

server {
    listen 8892
	server_name localhost;
	error_log  logs/error.log  debug;
	#root html/;
	default_type text/plain;
	merge_slashes off;
	
    
	location = /Test1 {
		return 200 'exact match!\n';
	}

	location ^~ /Test1/ {
		return 200 'stop regular expressions match!\n';
	}

	location ~ /Test1/$ {
		return 200 'first regular expressions match!\n';
	}

	location ~* /Test1/(\w+)$ {
		return 200 'longest regular expressions match!\n';
	}


    location /Test1/Test2 {
            return 200 'longest prefix string match!\n';
    }

    location /Test1 {
            return 200 'prefix string match!\n';
    }
}

# 测试代码
curl localhost:8892/Test1 # = 等号匹配
#exact match!

curl localhost:8892/Test1/ # ^~非正则匹配
# stop regular expressions match!

curl localhost:8892/Test1/Test2 # 最长正则匹配 不区分大小写 ~* /Test1/(\w+)$
# longest regular expressions match!

curl localhost:8892/test1/Test2 # 最长正则匹配 不区分大小写 ~* /Test1/(\w+)$
# longest regular expressions match!

curl localhost:8892/Test1/Test2/ # 最长匹配  
# longest prefix string match

10.preaccess 阶段

1. 限制每个客户端的并发连接数

ngx_http_limit_conn_module模块

模块:http_limit_conn_module

默认编译进nginx,通过 --without-http_limit_req_module 禁用

生效范围:

  • 全部worker进程(基于共享内存)0
  • 进入preaccess阶段前不生效
  • 限制的有效性取决于key的设计: 依赖postread阶段的realip模块取到真实ip

limit_conn 指令

限制发生时的日志级别
定义共享内存 (包括大小) ,以及key关键字
Syntax: limit_conn_zone key zone=name:size;
Context: http

限制并发连接数
Syntax: limit_conn zone number;
Context: http, server, location

限制发生时的日志级别 
Default: limit_conn_log_level error; # info | notice | warn | error;
Context: http, server, location

限制发生时向客户端返回的错误码
limit_conn_status 503;
Context: http, server,location

限制每个客户端的每秒处理请求数

ngx_http_limit_req_zone_module 模块

默认编译进nginx,通过--without-http_limit_req_zone_module禁用功能

生效算法: leaky bucket 算法

生效范围 和 limit_conn 一致

流量分类

  1. 突发性 bursty flow 比喻水龙头打开 ,一次性接收很多请求,立马处理,导致中间的请求无法响应。
  2. 修复均匀流量 fixed flow 漏斗式水盆接收后,按固定流量输出。不是立马处理,按均匀分布后,有序执行。

limit_req 指令

# 定义共享内存 (包括大小),以及 key 关键字和限制速率
limit_req_zone key zone=name:size rate=rate ;  # rate单位为r/s或者r/m

# 限制并发连接数
limit_req zone=name [burst-number] [nodelay]:
context:http, server, location

burst #默认为0
nodelay #对burst中的请求不再采用延时处理的做法,而是立刻处理

limit_req_log_level error;   #限制发生时的日志级别 
limit_req_status 503; #限制发生时向客户端返回的错误码 

例子

limit_conn_zone $binary_remote_addr zone=addr:10m;  # 定义 addr 指定空间大小为10m,超过后通过LRU算法调整
limit_req_zone $binary_remote_addr zone=one:10m rate=2r/m; # 定义 one ,指定空间大小为10m,每分钟处理两个请求
server {
    listen 8893;
    server_name localhost;
    root html/;
    error_log logs/myerror.log info; #  
    location /{
        limit_conn_status 500; # 默认503
        limit_conn_log_level  warn; # info | notice | warn | error; # 默认error
        limit_req_log_level  error; # info | notice | warn | error; # 默认error

        #limit_rate 50; # 限制50字节
        #limit_conn addr 1; # 每次只能有一个同时并发

        limit_req_status 503; # 默认503
        #limit_req zone=one; # 直接引用上面定义个 one,每分钟处理两个请求。
        limit_req zone=one burst=3; # 当一分钟内超过2个正在进行的请求,则会放入队列,等待正在运行的2个请求结束后,再统一执行队列的任务,队列长度为3
        limit_req zone=one burst=3 nodelay; # 队列里面的内容不等待,跟正在运行的两个任务一起发给后台处理。 
	}
}

# 同一分钟 请求2以上次 则提示 503 错误 503 Service Temporarily Unavailable
curl localhost:8893/ 
curl localhost:8893/
curl localhost:8893/

11.access阶段

用户授权

模块: http_access_module,默认编译进nginx

限制ip访问权限

server {
    listen 8894;
    server_name localhost;
    root html/;
    location / {
        deny 192.168.0.13; #限制不能访问ip
        allow 192.168.0.0/24; # 允许的 ip段
        deny all; # 剩余的都限制不能访问
    }
}

# 注意本地测试 对应的localhost 和 127.0.0.1 都要配置上去才生效

curl 192.168.0.7:8894  #  允许访问
curl localhost:8894  # 被限制
curl 127.0.0.1:8894 #  被限制

HTTP Basic Authentication

auth basic 模块的指令

基于HTTP Basic Authutication 协议进行用户名密码的认证

生成密码文件

# 1.定义文件
vi myfile1
# 输入内容
# comment
namel:password1
name2:password2:comment
name3:password3
 
# 2. 生成工具:htpasswd
yum install httpd-tools
htpasswd -cb myfile1  jason 123456

auth_request

# 安装
./configure --with-http_auth_request_module

# 效果
向上游的服务转发请求,若上游服务返回的响应码是2xx,则续执行,若上游服务返回的是401或者403,则将响应返回给客户端
# 原理
收到请求后,生成子请求,通过反向代理技术把请求传递给上游服务

auth_request_set # 可以设置请求参数

satisfy 指令

  • satisfy all 来控制多个条件是否必须完全满足才放行
  • satisfy any 只要有一个满足就才放行
Syntax: satisfy all/any; # 默认 all;

例子

# 上游服务器
server {
    listen 8090;
	server_name localhost;
    location /auth_upstream {
        return 200 'auth sucess'
    }
}

# 下游验证服务器
server {
    listen 8895;
    server_name localhost;
    error_log  logs/error.log  debug;
    root html/;
    default_type text/plain;
    location /auth_basic {
        satisfy any; # 这里 有两个验证 一个是 auth_basic, 一个是 deny 默认拒绝 ,如果 auth_basic验证通过会忽略deny拒绝,进行放行。
        auth_basic "test auth_basic";
        auth_basic_user_file myfile1; # 这里配置刚刚生成的包含用户和密码文件
        deny all; # deny 不一定生效
    }

    location / {
        auth_request /test_auth; # 通过上游的200 和 其他状态区分
    }

    location = /test_auth {
        proxy_pass http://127.0.0.1:8090/auth_upstream;
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        proxy_set_header X-Original-URI $request_uri;
    }
}

# 测试auth_basic 使用浏览器
http://localhost:8895/auth_basic
# 输入用户名 jason
# 输入用户密码 123456

# 测试 上游验证 
curl localhost:8895/ 
# 上游返回200 则成功
# 如果上游返回其他状态则失败

12.precontent

try_files 指令

按序访问资源的try_files模块

try_files file ... uri;

try_files file ... =code;

原理

依次试图访问多个url对应的文件,由root或者alias指令指定当文件存在时直接返回文件内容, 如果所有文件都不存在,则按最后一个URL结果或者code返回。

例子

server {
    listen 8896;
    server_name localhost;
    error_log  logs/myerror.log  info;
    root html/;
    default_type text/plain;
    location /first { # 尝试多个uri 都没有则返回最后一个
       # $uri 为 /first
       # $uri/index.html 为  /first/index.html
       # $uri.html 为  /first.html
        try_files /aa/bbb.html $uri $uri/index.html $uri.html @lasturl;
    }

    location @lasturl { # 本地内部定义的跳转,外网不能直接调用
        return 200 'lasturl!\n';
    }

    location /second {
        try_files $uri $uri/index.html $uri.html =404;
    }
}

curl localhost:8896/first
# 返回 lasturl

curl localhost:8896/second
# 返回 404 

mirror模块

实时拷贝流量,处理请求时,生成子请求访问其他服务,对子请求的返回值不做处理,默认在编译nginx

mirror uri/off; # 默认off  
mirror_request_body on/off; # 默认on

例子

# 这是 复制主服务器的流量分发服务
server {
    listen 10020;
    location / {
        return 200 'mirror response!';
    }
}

# 主服务器 入口主服务器
server {
    listen 8897;
    server_name localhost; 
    location / {
        mirror /mirror;
        mirror_request_body off;
        proxy_pass http://127.0.0.1 # # 指定处理主流量的后端Server 可以不设置
    }
    location = /mirror {
    internal; # 标志该location只为内部的重定向服务, 外面来的返回404
        proxy_pass http://127.0.0.1:10020/$request_uri; # 需要显示指明,因为流量复制过来之后会丢掉request_uri
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        proxy_set_header X-Original-URI $request_uri;
     }
}

#测试
curl 127.0.0.1:8897/index.html 
# 输出 首页信息 

tail -f 100 ./logs/access.log 
#查看两台服务器都分别请求了 index.html  页面 

13.content阶段

root和alias指令

### alias
将url映射为文件路径,以返回静态文件内容
Context: location

### root
root会将完整ur映射进文件路径中 
alias只会将location后的URL映射到文件路径
Context: http, server, location, if in location

root 和 alias的区别

# 1. root 指的是 完整的路径
location /c/ {
    root /a/
} 
# 对应路径是绝对的 /a/c/

# 2. alias 指的是虚拟路径
location /c/ {
    alias /a/
} 
# 对应路径是 /c/ 是虚拟的,只访问/a/ 下面的文件 

例子

server {
    listen 8898
    server_name localhost;
    error_log  logs/myerror.log  info;

    location /root {
        root html;
    }
    location /alias {
        alias html;
    }
    location ~ /root/(\w+\.txt) {
        root html/first/$1;
    }
    location ~ /alias/(\w+\.txt) {
        alias html/first/$1;
    }
    location  /RealPath/ { # 检查当前返回的路径 
        alias html/realpath/;
        return 200 '$request_filename:$document_root:$realpath_root';
        # $request_filename 为当前请求的完整路径 /usr/local/nginx/html/realpath/RealPath/1.txt
        # $document_root 为当前请求的alias或者 root的路径 /usr/local/nginx/html/realpath
        # $realpath_root 将document_root中的软链接等换成真实路径  /usr/local/nginx/html/first
    }
}

# 创建测试数据
echo 'test1' ./html/1.txt 

curl 127.0.0.1:/root/ # 等价于 html/root/index.html  所以返回404
curl 127.0.0.1:/root/1.txt  # 等价于 html/root/1.txt  所以返回404

curl 127.0.0.1:/alias/   # 等价于 html/index.html  所以返回首页
curl 127.0.0.1:/alias/1.txt  # 等价于 html/1.txt  所以返回首页 test1

curl 127.0.0.1:8898/RealPath/1.txt
# 输出
#/usr/local/nginx/html/realpath/RealPath/1.txt:/usr/local/nginx/html/realpath:

content-type

Context: http, server, location

Syntax: types { ... }
Default: types { text/html html; image/gif gif; image/jpeg jpg; } 

Syntax: default_type mime-type;
Default: default_type text/plain; 

Syntax: types_hash_bucket_size size;
Default: types_hash_bucket_size 64; 

Syntax: types_hash_max_size size;
Default: types_hash_max_size 1024;

未找到文件时的错误日志

log_not_found on/off ; # on

url结尾 自动加 / 访问

static 模块实现了 root/alias 功能时, 发现访问目标是目录,但 URL 末尾未加/时,会返回 301 重定向

重定向跳转的域名

Syntax: server_name_in_redirect on | off; # 默认 off 
Context: http, server, location

Syntax: port_in_redirect on | off; # 默认on 
Context: http, server, location

Syntax: absolute_redirect on | off; # 默认on
Context: http, server, location

例子

server {
    listen 8300;
    server_name test1.com test2.com;
    server_name_in_redirect off; # 重定向是否带域名
    port_in_redirect on; # 重定向是否带上端口的开关
    absolute_redirect off; # 默认on  ,off 时候返回相对地址  
    root html/;
}

curl localhost:8300/first2 -I 
# 301 重定向到  absolute_redirect off 返回相对地址 
# /first/

# 当 absolute_redirect on 设置为on, 返回绝对地址 
# 301 重定向到  
# http://localhost:8300/first/

# 当添加 Host 头部信息
curl -H 'Host:test111' localhost:8300/first -I
# 返回 
http://test111:8300/first/

# 当 server_name_in_redirect on; 设置为on,则重定向 会重新向到第一个域名
curl localhost:8300/first2 -I 
# 301 重定向到  
# http://test1.com:8300/first/
# 指定host 也改变不了
curl -H 'Host:test111' localhost:8300/first -I
# http://test1.com:8300/first/

index/random_index/autoindex

## index
# 指定 / 访问时返回index文件内容
index index.html; 

### random_index
# 默认不在Nginx
random_index  off; 

### autoindex 
## 默认在nignx里
Syntax: autoindex off; 
Syntax: autoindex_exact_size on;
Syntax: autoindex_format html ; # html | xml | json | jsonp;
Syntax: autoindex_localtime off ;  

例子

server {
    listen 8301;
    server_name localhost;
    location / {
        alias html/;
        autoindex on;  
        index a.html;  # 注意如果当前文件夹有index.html,  这里必须指定index 并指定不存在的xx.html,不然 index 默认是 index.html 导致无法访问文件夹
        autoindex_exact_size off; # 显示文件实际大小
        autoindex_format html; # 按指定格式显示 文件列表信息
        autoindex_localtime on; # on 显示的文件时间为文件的服务器时间  , off 为显示的文件时间为GMT时间
    }
}

 curl localhost:8301
 # 显示文件列表 

# 当 注释 index a.html,则 autoindex不会生效
 curl localhost:8301 
# 则显示a.html 页面

concat

功能 :当页面需要访问多个小文件时,把它们的内容合并到一次http响应中返回,提升性能

安装

wget https://codeload.github.com/alibaba/nginx-http-concat/zip/refs/heads/master
unzip nginx-http-concat-master.zip

mkdir -p /usr/local/download/nginx-1.15.8/module
mv nginx-http-concat-master /usr/local/download/nginx-1.15.8/module
#编译
./configure --add-module=./module/nginx-http-concat-master

使用

在URI 后加上??,后通过多个逗号分隔文件。如果还有参数,则在最后通过?添加参数

test1.com/??a.js,b.js…

分析淘宝网

例子

server {
    listen 8302
	server_name localhost;
	error_log logs/myerror.log debug;
	concat on;
	root html; 
    location /concat { #访问文件路径为 html/concat
        concat_max_files 20; #设置合并的最大文件数为20
        concat_types text/plain;  #允许合并的文件类型
        concat_unique on; #只允许同类文件合并
        concat_delimiter ':::'; # 返回 分割的符号
        concat_ignore_file_error on;
    }
}

# 创建测试文件
cd html
mkdir concat
echo 'test1' > ./concat/1.txt;
echo 'test2' > ./concat/2.txt;
curl localhost:8302/concat/??1.txt,2.txt
# 输出内容
# test1:::test2

# js 分割实例
cd html
# 创建 index.html
echo '<html><script src="./??a.js,b.js"> </script></html>' >  ./concat/index.html
# 创建js 
echo 'document.write("aaaa")' > ./concat/a.js;
echo 'document.write("bbbb")' > ./concat/b.js;
# conf 配置 
concat_delimiter ''; # 去除分割符

# 在浏览器访问
http://localhost:8302/concat/
# 输出 
# aaaabbbb

14.log阶段

access.log

将HTTP请求相关信息记录到日志 ngx_http_log_module 无法禁用

Syntax: log_format name [escape=default|json|none] string ...;
Default: log_format combined "...";
Context: http

log_format combined '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent ' '"$http_referer"
"$http_user_agent"';

日志格式

Syntax: access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
access_log off;
Default: access_log logs/access.log combined;
Context: http, server, location, if in location, limit_except

日志路径

注意点

  • path 路径可以包含变量:不打开 cache 时每记录一条日志都需要打开、关闭日志文件
  • if 通过变量值控制请求日志是否记录

日志缓存

  • 功能:批量将内存中的日志写入磁盘
  • 写入磁盘的条件
  1. 所有待写入磁盘的日志大小超出缓存大小
  2. 达到 fush 指定的过期时间
  3. worker 进程执行reopen 命令,或者正在关闭

日志压缩。

  • 功能:批量压缩内存中的日志,再写入磁盘
  • buffer 大小默认为64KB
  • 压缩级别默认为 1 (1 最快压缩率最低,9 最慢压缩率最高)

日志文件名包含变量时的优化

Syntax: open_log_file_cache max=N [inactive=time] [min_uses=N] [valid=time];
open_log_file_cache off;
Default: open_log_file_cache off;
Context: http, server, location
  • max : 缓存内的最大文件句柄数,超出后用 LRU 算法淘汰
  • inactive : 文件访问完后在这段时间内不会被关闭。默认 10 秒
  • min_uses : 在inactive 时间内使用次数超过 min uses 才会继续存在内存中。默认 1超出 valid 时间后,将对缓
  • valid : 存的日志文件检查是否存在。默认 60 秒
  • off : 关闭缓存功能