Server和Location解析(四)

发布于:2023-01-12 ⋅ 阅读:(227) ⋅ 点赞:(0)

背景:

        前面简单的说了如何配置nginx做虚拟主机,我们知道定义一个虚拟主机需要先配置server块去匹配访问的URL地址中的域名,然后在配置location块,匹配访问的URL地址中的URI,下面就展开说说Server块和location。

 Server解析

1.     Server是什么?

        前面我们一直说nginx配置虚拟主机,严格意义上就是配置一个server块,一个server块就定义了一个web服务。当前端通过URL来访问web服务的时候,nginx通过域名来匹配有哪个server块处理请求。即server是用来匹配URL中的域名,从而判断有哪个server块来处理请求。

2.    Server块解析 

    2.1     让我们从一个简单的配置开始,以下三个虚拟服务器都侦听端口 *:80

server {
    ##  设置监听端口
    listen      80;

    ## 设置URL的域名匹配
    server_name example.org www.example.org;
    ...
}

server {
    listen      80;
    server_name example.net www.example.net;
    ...
}

server {
    listen      80;
    server_name example.com www.example.com;
    ...
}

         在此配置中,nginx 通过server块中的server_name参数来测试请求的标头字段“Host”,以确定应将请求路由到哪个服务器。如果它的值不匹配任何服务器名称,或者请求根本不包含这个头域,那么 nginx 会将请求路由到这个端口的默认服务器。

        在上面的配置中,默认服务器是第一个——这是 nginx 的标准默认行为。也可以使用listen指令中的default_server参数明确设置哪个服务器应该是默认的:

server {
    listen      80 default_server;
    server_name example.net www.example.net;
    ...
}

        如果不允许没有“Host”头字段的请求,可以定义一个只丢弃请求的服务器:

server {
    listen      80;
    server_name "";
    return      444;
}

        在这里,服务器名称设置为一个空字符串,它将匹配没有“Host”头字段的请求,并返回一个特殊的 nginx 的非标准代码 444 来关闭连接。

2.2  看一个更复杂的配置,其中一些虚拟服务器侦听不同的地址:

server {
    listen      192.168.1.1:80;
    server_name example.org www.example.org;
    ...
}

server {
    listen      192.168.1.1:80;
    server_name example.net www.example.net;
    ...
}

server {
    listen      192.168.1.2:80;
    server_name example.com www.example.com;
    ...
}

         在此配置中,nginx 首先根据服务器块的侦听指令测试请求的 IP 地址和端口。然后,它根据与 IP 地址和端口匹配的服务器块的 server_name 条目匹配测试请求的“Host”标头字段。如果未找到服务器名称,则请求将由默认服务器处理。例如,在 192.168.1.1:80 端口收到的对 www.example.com 的请求将由 192.168.1.1:80 端口的默认服务器处理,即由第一台服务器处理(没有设置listen  decault_server),因为没有 www.example .com 为该端口定义。

默认服务器是监听端口的一个属性,并且可以为不同的端口定义不同的默认服务器

3.  配置示例

        定义两个server块,其中第二个server块中配置listen  default_server

server {
	listen 80;
    server_name xhz.com,www.xhz.com;
    access_log /var/log/nginx/host.access.log main;
    autoindex on;

    location / {
        root /nginx/xhz;
        index index.html;
        
    }
}

server {
	listen 80 default_server;
    server_name flf.com,www.flf.com;
    access_log /var/log/nginx/host.access.log main;
    autoindex on;

    location / {
        root /nginx/flf;
        index index.html;
        
    }
}

 1)通过www.xhz.com访问时

 

 2)通过www.flf.com访问时

 3) 通过www.xjl.com访问时,此时匹配不到server_name

 Location解析

 1.  什么是Location?

        location是用来控制URI的访问路径的。当访问的URL中的域名与server块中的sererv_name匹配之后,将请求转发到相应的服务器块,随后进行URL中的URI部分匹配,由于server块中可以有多个location,从而确定由哪个location进行处理。

2.    Location的匹配规则

 2.1   语法

location [ = | ~ | ~* | ^~ ] uri {
     ... 
}

location @name {
     ... 
}

2.2    匹配规则

        位置可以由前缀字符串或正则表达式定义。正则表达式使用前面的“~*”修饰符(用于不区分大小写的匹配)或“~”修饰符(用于区分大小写的匹配)指定。为了找到与给定请求匹配的位置,nginx 首先检查使用前缀字符串(前缀位置)定义的位置。其中,匹配前缀最长的位置被选中并记忆。然后按照它们在按照配置文件中出现的顺序检查正则表达式。正则表达式的搜索在第一次匹配时终止,并使用相应的配置。如果找不到与正则表达式的匹配项,则使用前面记住的前缀位置的配置。

即:1)先匹配前缀最长,童通俗的说就是匹配度最高的 location;2)然后再按照配置文件中出现的顺序检查正则表达式。正则表达式的搜索在第一次匹配时终止,并使用相应的配置。如果找不到与正则表达式的匹配项,则使用前面记住的最长匹配

规则 用法  优先级
= 精准匹配  1
^~ 以某个字符串开头 2
~ 区分大小写的正则匹配 3
/ 通用匹配,任何请求都会匹配到 4
~* 不区分大小写的正则匹配 5

2.3   匹配示例

location  = / {
    # 只精准匹配 / 的查询.
  [ configuration A ] 
}
# 匹配成功: / 

location / {
    # 匹配任何请求,因为所有请求都是以”/“开始
    # 但是更长字符匹配或者正则表达式匹配会优先匹配
  [ configuration B ] 
}
#匹配成功:/index.html

location /documents {
    # 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索/
    # 只有后面的正则表达式没有匹配到时,这一条才会采用这一条/
  [ configuration C ] 
}
# 匹配成功:/documents/document.html
# 匹配成功:/documents/abc

location ~ /documents/ABC {
    # 区分大小写的正则匹配
    # 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索/
    # 只有后面的正则表达式没有匹配到时,这一条才会采用这一条/
  [ configuration CC ] 
}

location ^~ /images/ {
    # 匹配任何以 /images/ 开头的地址,匹配符合以后,立即停止往下搜索正则,采用这一条。/
  [ configuration D ] 
}
# 成功匹配:/images/a.gif

location ~* \.(gif|jpg|jpeg)$ {
    # 匹配所有以 .gif、.jpg 或 .jpeg 结尾的请求,不区分大小写
    # 然而,所有请求 /images/ 下的图片会被 [ config D ]  处理,因为 ^~ 到达不了这一条正则/
    [ configuration E ] 
}
# 成功匹配:/documents/a.jpg

location /images/ {
    # 字符匹配到 /images/,继续往下,会发现 ^~ 存在/
  [ configuration F ] 
}

location /images/abc {
    # 最长字符匹配到 /images/abc,继续往下,会发现 ^~ 存在/
    # F与G的放置顺序是没有关系的/
  [ configuration G ] 
}

location ~ /images/abc/ {
    # 只有去掉 [ config D ] 才有效:先最长匹配 [ config G ] 开头的地址,继续往下搜索,匹配到这一条正则,采用/
    [ configuration H ] 
}

        “/”请求将匹配配置 A,“/index.html”请求将匹配配置 B,“/documents/document.html”请求将匹配配置 C,“/images/1.gif”请求将匹配配置 D,“/documents/1.jpg”请求将匹配配置 E。

 2.3   命名Location

         带有 @ 的 location 是用来定义一个命名的 location,这种 location 不参与请求匹配,一般用在内部定向。

location / {
    try_files $uri $uri/ @custom
}

location @custom {
    # ...do something
}


##  分析try_files $uri $uri/ @custom:
1. 假设我定义的 root 为 /usr/share/nginx/html/,访问的 URI 是 /hello/xhz
2. 当 URI 被匹配后,会先查找 /usr/share/nginx/html//hello/shiyanlou 这个文件是否存在,如果存在则返回。
3.查找 /usr/share/nginx/html//hello/xhz/ 目录是否存在,如果存在,按 index 指定的文件名进行查找,比如 index.html,如果存在则返回。
4. 上面都不存在的时候,则会执行location @custom 中定义的内容。

2.4 location URI结尾带不带 /

         对于请求URI结尾是否带有/,一般的处理逻辑是带/表示访问目录,不带/表示访问文件,如果文件不存在也会去匹配目录。如访问http://www.nginx.cn/images/和http://www.nginx.cn/images,前面的请求会匹配目录,后面的请求会先匹配文件,文件不存再匹配目录

        对于locatioin中的URI来说,如果URI的结尾带有/,并且location要执行的命令式是proxy_pass、fastcgi_pass、uwsgi_pass、scgi_pass、memcached_pass、grpc_pass之一。

location /user/ {
    proxy_pass http://user.example.com;
}

         对于这种情况,nginx会做特殊处理,不管user命名的文件或目录存在不在,如果你访问http://www.nginx.cn/user会被重定向到http://www.nginx.cn/user/

因此想这两种请求对应不同的处理,就要明确增加不带/结尾的location配置,如下

location /user/ {
    proxy_pass http://user.example.com;
}

location = /user {
    proxy_pass http://login.example.com;
}

 示例:

server {
	listen 80;
    server_name user.com www.user.com;
    access_log /var/log/nginx/host.access.log main;
    autoindex on;

location /user {
    root /nginx/user;
    index index.html;
}

location = /user/ {
    root /nginx/user;
    index index.html;
}

}

##  返回结果
## 返回301是因为/nginx/user目录下没有user的文件
C:\Users\xhz>curl www.user.com/user
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.22.0</center>
</body>
</html>

C:\Users\xhz>curl www.user.com/user/
user test


##备注
  1.  配置中的字符有没有 / 都没有影响。也就是说 /user/ 和 /user 是一样的。
  2. 如果 URI 结构是 https://xhz.com/ 的形式,尾部有没有 / 都不会造成重定向。因为浏览器在发起请求的时候,默认加上了 / 。虽然很多浏览器在地址栏里也不会显示 / 
  3. 如果 URI 的结构是 https://xhz.com/user/ 。尾部如果缺少 / 将导致重定向。因为根据约定,URL 尾部的 / 表示目录,没有 / 表示文件。所以访问 /user/ 时,服务器会自动去该目录下找对应的默认文件。如果访问 /user 的话,服务器会先去找 user 文件,找不到的话会将 user 当成目录,重定向到 /user/ ,去该目录下找默认文件。

2.4  Location的访问控制

        nginx的deny和allow指令是由ngx_http_access_module模块提供,Nginx安装默认内置了该模块。

语法:

语法:allow/deny address | CIDR | unix: | all

它表示,允许/拒绝某个ip或者一个ip段访问.如果指定unix:,那将允许socket的访问。
注意:unix在1.5.1中新加入的功能。

在nginx中,allow和deny的规则是按顺序(从上至下)执行的,只要有一个匹配上就不会向下匹配。

示例:

示例1:
location /
{
    allow 192.168.0.0/24;
    allow 127.0.0.1;
    deny all;
}

说明:这段配置值允许192.168.0.0/24网段和127.0.0.1的请求,其他来源IP全部拒绝。

示例2:
location = /user/ {
    root /nginx/user;
    index index.html;
    allow all;
    deny 192.168.65.1;
}
说明:当192.168.65.1访问时由于allow all已经匹配上允许所有,所以不会在向下匹配。

后续即将说到的nginx配置反向代理和负载均衡等功能,实际都是通过配置location来实现相应的功能,因此我们熟练掌握location的匹配规则。

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到