1. 配置说明
/usr/local/nginx/conf/nginx.conf
#user nobody;
worker_processes 1;
error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
# default_type application/octet-stream;
default_type text/plain;
log_format p '$remote_addr - $remote_user [$time_local] "$request" ';
log_format access '$remote_addr ';
access_log logs/access.log p;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/*.conf;
}
注意下面的配置都要放在other.conf.d目录下面, 不能和nginx.conf配置在同一目录,因为使用了include /etc/nginx/*.conf;(和nginx.conf也是匹配的)
/usr/local/nginx/conf/other.conf.d/a.conf
server {
listen 81;
server_name a.com;
# access_log logs/access_enjoy.log access;
location / {
root /etc/nginx/html;
index a.html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
/usr/local/nginx/conf/other.conf.d/b.conf
server {
listen 81; # default_server;
server_name b.com;
location / {
root /etc/nginx/html;
index b.html;
}
location /echo {
echo 'I am b';
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
/usr/local/nginx/conf/other.conf.d/c.conf
server {
listen 8080;
server_name c.com;
location / {
root /etc/nginx/html;
index c.html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
dns配置
127.0.0.1 a.com
127.0.0.1 b.com
127.0.0.1 c.com
127.0.0.1 z.com
2. 先说我的结论
由于自己使用的本机的docker desktop, 开始对于dns和server_name好迷糊,导致开始配置总是有的可以访问有的不能访问
问题本质是我对dns的域名和server_name的理解有问题, 我们的域名和server_name两个虽然是同一个字符串, 但是在这个网络过程中不同阶段作用是不一样的, 由于我使用的本机, 开始以为nginx会帮我做类似dns注册解析功能, 所以开始一致有问题
示例: http://you.com:81(假设docker映射端口是 81->81)
当我们本机使用域名访问时候,同样需要dns解析,并且千万记住, 我们的那个nginx中的server_name不能参与任何的dns的解析过程(nginx的server_name也有自己的作用, 后面再说),
- 我们的域名通过本机的hosts解析出ip(因为docker在本机,所以我们配置必须是127.0.01 you.com之类),
- 然后请求拿着127.0.0.1知道要在本机访问, 于是拿着个81->81端口进入了docker的81端口, 匹配server的listen端口(这一步并不是去匹配域名, 也是为什么listen写在了server_name前面)
- 如果所有的server只有一个和81端口匹配, 就直接命中这个server, 然后进行location解析
- 如果没有server和这个81端口匹配, 直接拒绝请求
- 如果有多个server和81端口匹配
server_name和域名相同的server优先匹配
如果没有server_name和域名匹配, 就使用默认server(如 listen 81 default_server;)
如果没有指定默认server, 就命中匹配的第一个server(同一个配置从上到下, 不同文件,文件名字典序)命中
从上面的过程中,我们可以看出来,域名只在dns解析时候其到很重要的作用,一旦我们解析找到了主机时候,域名作用就没了, 所以说端口代表了一个处理程序, server list port放在第一位, default_server放在端口后面而不是server_name后面,都充分体现了端口的重要性,所以只要端口命中就一定会有一个server来location这个请求(能不能处理这个请求还要看后面的匹配), 甚至我们不配置server_name 这个server同样可以工作
总之, 域名用于dns找到主机, 端口用来找到server, server_name只是在配置了多个相同端口的server时候起到一个过滤选择的作用,非必须的
3. 基于上面的理解,我们来验证
将b.conf的server配置成default_server时候
http://b.com:81/
结果
http://a.com:81/
结果
http://z.com:81/ (注意没有z.com的server_name)
结果
不设置default_server时候
http://b.com:81/
结果
http://a.com:81/
结果
http://z.com:81/ (注意没有z.com的server_name)
结果: 注意,由b.html变成了a.html
http://c.com:8080/
结果: 下一个测试基于这个结果参照
上面测试结果知道了: 端口冲突, server_name筛选, default_server作为兜底条件, 保证一定能选出一个
测试端口命中, server_name不命中的情况
http://a.com:8080/
http://b.com:8080/
http://z.com:8080/
三个结果都是
这个测试说明端口命中就没有server_name和default_server什么事了
4. location理解
#location指令优先级验证:
# =精准匹配,最优,匹配就直接返回
# ^~,空 为一般匹配,收集所有匹配,取最长匹配执行(此时不返回,还会执行下面的正则匹配)
# ~,~* 为正则匹配,按顺序依次匹配,命中即返回(可能会覆盖普通匹配)
server {
listen 80;
server_name loc.com;
#精准匹配测试
#第1,2条虽然匹配,但第三条是精准匹配,出第三条结果
#测试路径/equal/a/b/c
location ~ /equal/* {#被命中,但被下面的推断:location = /equal/a/b/c
echo '/equal/*';
}
location /equal/a/b {#被命中,但被下面的推断:location = /equal/a/b/c
echo '/equal/a/b';
}
location = /equal/a/b/c {#被命中,直接执行,不等待
echo '/equal/a/b/c';
}
#普通匹配测试
#第1,2条虽然匹配,第三条匹配更长,出第三条结果
#测试路径/match/a/b/c
location /match/a {#被命中,但不是最长
return 200 "/match/a";
}
location /match/a/b {#被命中,但不是最长
return 200 "/match/a/b";
}
location /match/a/b/c {#被命中,且最长
return 200 "/match/a/b/c";
}
location /match/a/b/c/d {#不命中
return 200 "/match/a/b/c/d";
}
#正则匹配覆盖普通匹配测试
#会覆盖普通匹配,不会覆盖=和^~
location =/re/a.js {#访问/re/a.js,不会被后面的正则覆盖
echo 'match =';
}
location ^~ /re/a/b {#访问/re/a/b开头的路径,不会被后面的正则覆盖
echo 'math ^~/re/a/b*';
}
location /re/a.htm {#访问/re/a.htm,会被后面的正则覆盖
echo 'match /re/a.htm';
}
location ~ /re/(.*)\.(htm|js|css)$ {#覆盖/re/a.htm路径
echo "cover /re/$1.$2";
}
#正则匹配成功一条后,便不再走其它正则
#最长正则匹配是第三个,但匹配第一个后便不往下走
#测试路径/rex/a/b/c.htm
location ~ /rex/.*\.(htm|js|css)$ {#覆盖/re/a.htm路径
echo "match first";
}
location ~ /rex/a/(.*)\.(htm|js|css)$ {#覆盖/re/a.htm路径
echo "match second";
}
location ~ /rex/a/b/(.*)\.(htm|js|css)$ {#覆盖/re/a.htm路径
echo "match third";
}
location / {
root /etc/nginx/html;
index c.html;
}
}
5. proxy理解
server {
listen 80;
server_name pxy.com;
#后台服务原始路径:http://192.168.0.132:8088/mvc/index?id=2
#无/,访问路径:http://pxy.enjoy.com/mvc/index?id=2
location /mvc {
#此处未关闭,传递整个路径/nginx/enjoy/getInfo到目标ip:port
proxy_pass http://192.168.0.132:8088;
}
#有/,访问路径 :http://pxy.enjoy.com/nginx/mvc/index?id=2
location /nginx/mvc {#匹配路径/dynamic,剩余路径/nginx/enjoy/getInfo
proxy_pass http://192.168.0.132:8088/mvc;
}
#访问路径:http://pxy.enjoy.com/static/d.html
location /static {#匹配路径/static,剩余路径/a.html
root /etc/nginx/html/;#root声明,在html文件夹,查找/static/a.html文件
}
#访问路径:http://pxy.enjoy.com/target/d.html
location /target {#匹配路径/target,剩余路径/a.html
alias /etc/nginx/html/static/;##alias声明,在static/文件夹,查找a.html文件
}
}
6. rewrite理解
server {
listen 80;
server_name rew.com;
location /a.html {
echo 'I am a.html';
}
location /b.html {
echo 'I am b.html';
}
#此路径请求:http://rew.enjoy.com/aa.html
location /aa.html {##内部重定向
rewrite ^/ /a.html break;##停止指令,流程不变往下走
rewrite ^/ /b.html break;
root /etc/nginx/html/;
}
#此路径请求:http://rew.enjoy.com/ab.html
location /ab.html {
rewrite ^/ /a.html last;##停止指令,但重新location匹配
rewrite ^/ /b.html last;
rewrite ^/ /c.html;
root /etc/nginx/html/;
}
#此路径请求:http://rew.enjoy.com/bb
location /bb {
rewrite ^/ /b.html redirect;##302临时重定向
set $aa 12;
root html/;
}
#此路径请求:http://rew.enjoy.com/ba
location /ba {
rewrite ^/ /b.html permanent;##301永久重定向
root html/;
}
#此路径请求:http://rew.enjoy.com/cc.html
location /cc.html {
rewrite ^/ /c.html;##指令不停,继续往下
rewrite ^/ /b.html;
rewrite ^/ /a.html;##最后一条,生效的是这条
root /etc/nginx/html/;
}
}