gpt4 book ai didi

nginx简单实践:静态资源部署、URL重写【nginx实践系列之一】

转载 作者:撒哈拉 更新时间:2025-01-13 12:42:47 56 4
gpt4 key购买 nike

〇、前言

本文为 nginx 简单实践系列文章之一,主要简单实践了两个内容:静态资源部署、重写,仅供参考.

关于 Nginx 基础,以及安装和配置详解,可以参考博主过往文章:

https://www.cnblogs.com/hnzhengfy/p/Nginx.html  。

1、静态资源部署

当前项目的结构基本上都是前后端分离,前端的相关资源,如 html,js,css 或者图片,变更频率比较低但访问量比较大,若想保证系统性能,可以将这些文件放在指定目录下,通过 nginx 的 root 或 alias 配置方式来指定静态资源的路径.

基于高并发高性能的 ningx,用户就可以通过域名加路径的方式,高效快速的进行页面访问.

下面是一个简单的示例.

nginx 配置示例(部分):

server {
    listen       8080;  # 绑定端口
    server_name  localhost;
	
    charset utf-8;  # 指定字符集,不然 html 文件中的汉字会乱码
	
    location /test {  # 路径匹配规则
        alias  /usr/tmp/test; # 别名,将当期路径对应到新的目录中
        index  index.html index.htm;
    }

    location /test_2 {  # 路径匹配规则
        alias  /usr/tmp/test/test_2; # 别名,将当期路径对应到新的目录中
        index index.html index.htm;
    }
}

示例文件示例,文件位置为 /usr/tmp:

/usr/tmp/test/test_page.html 。

/usr/tmp/test/test_2/test_2_page.html 。

/usr/tmp/test/test_2/westlage.jpg 。

测试结果如下图:

参考:https://www.cnblogs.com/qingshan-tang/p/12763522.html 。

2、Rewrite:URL 重写

2.1 简介

rewrite 就是 URL 重写,是一个将传入的 web 重定向到其他 URL 的过程.

上一部分静态资源部署,主要用的是 location 相关配置来实现静态资源的直接访问,下面先看下 rewrite 和 location 的区别.

  • rewrite 和 location 比较

rewrite 更侧重于 URL 路径的重写和跳转,而 location 则侧重于请求路径的匹配和处理。在实际使用中,两者往往结合使用,以实现复杂的请求处理逻辑.

功能目的 。

rewrite 主要用于重写 URL 路径,可以实现内部跳转(不改变浏览器地址栏的URL)或外部跳转(使用 redirect 标志时),通常用于在同一域名内更改获取资源的路径.

location 用于匹配请求的 URL 路径,本身不实现跳转,而是对匹配到的路径进行相应的处理,如访问控制、反向代理或静态资源服务.

配置位置 。

rewrite 只能放在 server {}, location {}, if {} 中,并且只能对域名后边的除去传递的参数外的字符串起作用.

location 作为 server {} 块中的一个指令,可以基于请求字符串、虚拟主机名称(IP或域名)和URL进行匹配.

执行顺序 。

rewrite 在 server 块中的 rewrite 指令会首先执行,然后是 location 匹配,最后是 location 块中的 rewrite 指令.

location 直接根据请求的 URL 路径进行匹配,一旦匹配成功,就会执行对应的处理逻辑.

2.2 rewrite 的优势

  • 隐藏真实目录结构:通过隐藏服务器上的真实文件路径和目录结构,防止攻击者通过直接访问文件路径来获取敏感信息。
  • 规范化 URL:强制规范化 URL 格式既可以避免一些常见的安全漏洞,如路径遍历攻击(Directory Traversal)或路径参数欺骗等等,又可以保证 URL 格式的一致性。
  • 防止盗链:通过 Rewrite 可以实施防盗链策略,防止其他网站直接链接到本站的资源。这有助于减轻服务器负载,防止不法分子盗用网站的带宽,并提高资源的安全性。
  • HTTP 到 HTTPS 的强制重定向:可以确保数据在传输过程中的安全性。这是保障通信安全的一种有效手段,尤其对于涉及用户敏感信息的网站至关重要
  • 条件性重写:可以根据请求中的条件来选择是否进行重写,有助于实现访问控制和强化安全性。例如,只有特定 IP 范围的请求才允许进行某种操作。
  • 跨站点脚本(XSS)防护:Rewrite 可以对请求参数进行过滤或修改,防止恶意用户通过注入脚本来进行 XSS 攻击。对 URL 和参数进行适当的重写可以减轻 XSS 攻击的风险。
  • 统一资源标识符(URI)规范化:通过强制规范化 URI,可以防止攻击者尝试混淆或绕过安全策略。规范化的URI有助于提高应用程序的安全性,防范一些常见的攻击手法。
  • 避免敏感信息泄露:Rewrite 可以限制对某些敏感信息或文件的访问,确保只有授权用户能够获取特定内容。这有助于防止敏感信息泄露和未授权访问。

2.3 Rewrite 相关指令

Rewrite 相关指令有 if、rewrite、set、return.

2.3.1 if 语句

Nginx 中的 if 语句常用于实现精细的访问控制策略。例如,可以设置只有特定IP或内网IP可以访问某些资源,其他IP则被重定向到停服更新页面,也可以通过 if 语句实现 URL 重写、限制访问速度等功能.

# 基本语法
if (condition) {
    ……
}

在匹配中可以用的一些符号和常量:

# if 可以支持如下条件判断匹配符号
~             正则匹配(区分大小写)
~*            正则匹配(不区分大小写)
!~            正则不匹配(区分大小写)
!~*           正则不匹配(不区分大小写)
-f 和!-f      用来判断是否存在文件,! 表示不存在
-d 和!-d      用来判断是否存在目录
-e 和!-e      用来判断是否存在文件或目录
-x 和!-x      用来判断文件是否可执行

# 在匹配过程中可以引用一些 Nginx 的全局变量
$args            	请求中的参数
$document_root      针对当前请求的根路径设置值
$host            	请求信息中的 Host,如果请求中没有Host行,则等于设置的服务器名
$limit_rate        	对连接速率的限制
$request_method     请求的方法,比如 GET、POST 等
$remote_addr        客户端地址
$remote_port        客户端端口号
$remote_user        客户端用户名,认证用
$request_filename   当前请求的文件路径名(带网站的主目录 /usr/local/nginx/html/images/a.jpg)
$request_uri        用于表示客户端请求的完整 URI,也就是请求地址,它记录了客户端发起的请求地址
$query_string       与 $args 相同
$scheme             用的协议,比如 http 或者是 https
$server_protocol    请求的协议版本,HTTP/1.0 或 HTTP/1.1
$server_addr        服务器地址,如果没有用 listen 指明服务器地址,使用这个变量将发起一次系统调用以取得地址(造成资源浪费)
$server_name        请求到达的服务器名
$document_uri       与 $uri 一样,URI 地址
$server_port        请求到达的服务器端口号

后文将进行示例演示.

2.3.2 rewrite flag 简介:redirect、permanent、break、last

Nginx 中的 rewrite 指令可以包含一个可选的 flag(标志),用于控制重写操作后的行为.

这个 flag 的类型总共有四种,如下:

  • redirect:这是一种临时重定向,状态码为 302。当重写完成后,Nginx 会以临时重定向的方式返回重写后生成的新 URL 给客户端。浏览器地址栏会显示跳转后的 URL 地址,但爬虫不会更新 URL。
  • permanent:这是一种永久重定向,状态码为301。与 redirect 类似,permanent 也会直接对 URL 地址进行重定向,并显示跳转后的 URL 地址。从实现功能的角度看,redirect 和 permanent 是一样的,不存在好坏和性能上的问题。然而,对于 SEO(搜索引擎优化)来说,使用 permanent 更为友好,因为它告诉搜索引擎这是一个永久性的移动,把原始页面的所有排名信号都传递到新的URL上,无需再请求到原地址,也避免了地址栏的重复跳转,更友好。
  • break:在重写完成后,break 会停止处理当前 URL 在当前 location 以及其他 location 中后续的其他重写操作。它不会跳出 location 作用域,也不会重新搜索与更改后的 URI 相匹配的 location适用于一个 URL 只需要一次重写的场景。2
  • last:重写完成后,last 会停止处理当前 URI 在当前 location 中后续的其他重写操作。但它会对新的 URL 启动新一轮重写检查,并可能跳出当前 location 作用域搜索与更改后的 URI 相匹配的 location适用于一个 URL 可能需要多次重写的场景。

2.3.3 permanent 简单示例

注意:可以使用测试域名,但前提是要修改 hosts 文件.

路径和重启:Linux(/etc/hosts)(重启命令:/etc/init.d/network restart);Windows(C:\Windows\System32\drivers\etc\hosts).

  • 实例:变更整个资源路径

示例:从 http://www.testczzj.com:8080/test/test_page.html 。

——> http://www.testczzj.com:8080/test2/test2.html 。

示例文件夹结构:

/usr/tmp/test/test_page.html 。

/usr/tmp/test2/test2_page.html 。

<div id="div1">
	<h1>这是test2_page页面</h1>
</div>
server {
    listen       8080;
    server_name  www.testczzj.com;
    charset utf-8;
	
    location /test {
        index  index.html index.htm;
        # 匹配成功之后的全部路径,全部替换成指定的地址
        rewrite  .*  /test2/test2_page.html  permanent;
    }

    location /test2 {
        alias  /usr/tmp/test2;
        index index.html index.htm;
    }
}

自动跳转:(输入第一行地址回车自动跳转到新地址) 。

  • 实例:变更路径中的一部分

示例:http://www.testczzj.com:8080/2024/test/test_page.html 。

——> http://www.testczzj.com:8080/2025/test/test_page.html  。

目的就是将 URL 中的 /2024/ 自动换成 /2025/,当然,实际业务中可以一般没有这么简单.

示例文件夹结构:

/usr/tmp/2025/test/test_page.html 。

<div id="div1">
	<h1>这是test_page页面</h1>
</div>
server {
    listen       8080;
    server_name  www.testczzj.com;
    charset utf-8;
	
    location /2024/test {
        index  index.html index.htm;
        # 先匹配 2024 之后的全部路径,再拼接到 2025 之后
        rewrite  ^/2024/(.*)  /2025/$1  permanent; #  (.*):表示以任意结尾,全部匹配取到
    }

    location /2025/test2 {
        alias  /usr/tmp/test2;
        index index.html index.htm;
    }
}

自动跳转:(输入第一行地址回车自动跳转到新地址) 。

  • 实例:将旧域名永久重定向到新域名

示例:http://www.testczzj.com/2024/test/test_page.html 。

——> http://www.testczzj_new.com 。

根据路径中的标识:/2024,来拦截,将全部请求直接跳转到新的地址主页.

server {
    listen       8080;
    server_name  www.testczzj.com www.testczzj_new.com;
    charset utf-8;
	
    location /2024 {
        root /usr/tmp/2024
        index  index.html index.htm;
        if  ($host ~* www.testczzj.com){ # 将 testczzj 转到 testczzj_new
            rewrite .* http://www.testczzj_new.com permanent;
            }
    }
}

自动跳转:

  • 实例:只更新协议和域名,url 路径不变

示例目标:http://www.testczzj.com/2024/test/test_page.html 。

——> https://cn.bing.com/2024/test/test_page.html 。

配置如下:

server {
    listen       80;
    server_name  www.testczzj.com;
    charset utf-8;
	
    location /2024 {
       root /usr/tmp/2024;
       index  test_page.html  index.html  index.htm;
        if  ($host ~* www.testczzj.com){ # $request_uri 用于表示客户端请求的完整 URI,也就是请求地址
            rewrite .* http://cn.bing.com$request_uri permanent;
            }
    }
}

自动跳转:(由于 bing 后路径没有资源,因此页面会加载失败) 。

  • 实例:在 URL 地址末尾没有 / 时,默认添加

示例目标:http://www.testczzj.com/2024/test 。

——> http://www.testczzj.com/2024/test/ 。

注:示例文件路径:/usr/tmp/2024/test/test_page.html.

为什么要添加这个斜线?

搜索引擎对带有和不带有斜杠的 URL 有着不同的处理方式。通常,带有斜杠的 URL 被视为目录,而不带斜杠的 URL 被视为文件或特定资源.

当 URL 的斜杠使用不一致时,可能会导致不必要的重定向,从而影响页面加载速度和用户体验。一致的 URL 结构有助于提高用户体验。用户期望目录级别的 URL 以斜杠结尾,而文件级别的 URL 则不带斜杠.

server {
    listen       80;
    server_name  www.testczzj.com;
    charset utf-8;
	
    location /2024/test {
       root /usr/tmp;
       index  test_page.html  index.html  index.htm;
        if  (-d  $request_filename){ # 用于检查请求的文件名是否是一个目录。如果是目录,则执行大括号内的指令
            # (.*):捕获任意字符(除了换行符)零次或多次,并将其存储在第一个捕获组中
            # ([^/]):捕获除斜线(/)之外的任意单个字符,并将其存储在第二个捕获组中
            # $host:当前请求的主机名
            rewrite ^(.*)([^/])$ http://$host$1$2/ permanent; 
            }
    }
}

自动补上斜线:

  • 实例:重定向后,在 URL 末尾添加 Query 参数

示例目标:http://www.testczzj.com/login/czzj.html 。

——> http://www.testczzj.com/2024/test/login.html?name=czzj 。

示例文件路径:/usr/tmp/2024/test/login.html.

把功能隐藏到 URL 路径中去.

server {
    listen       80;
    server_name   www.testczzj.com;
    charset utf-8;

    location /login {
       root /usr/tmp/2024;
       index  login.html  index.html  index.htm;
       # 正则表达式的目的:匹配以 /login/ 开头并以 .html 结尾的内容为第一捕获组:$1
       rewrite ^/login/(.*)\.html$ http://$host/test/login.html?name=$1;
    }

    location /test { # 处理重写后的请求:/test
            alias  /usr/tmp/2024/test;
            index  login.html  index.htm;
    }
}

如下图自动跳转:

  • 实例:将固定格式 /2025-01-02/ 重定向为 /2025/01/02/

示例目标:http://www.testczzj.com/test/2025-01-03/test_page.html 。

——> http://www.testczzj.com/test/2025/01/03/test_page.html 。

示例文件路径:/usr/tmp/test/2025/01/03/test_page.html 。

server {
    listen       80;
    server_name   www.testczzj.com;
    charset utf-8;

    location /test {
       root /usr/tmp;
       index  test_page.html  index.html  index.htm;
       # ([0-9]+): 这是一个捕获组,用于匹配一个或多个数字(即至少一个数字)
       # (.*): 这是第四个捕获组,用于匹配任意数量的任意字符(包括空字符)
       rewrite ^/test/([0-9]+)-([0-9]+)-([0-9]+)(.*)$ /test/$1/$2/$3$4 permanent;
    }
}

如下图自动跳转:

2.4 set 指令

set 指令用于设置一个变量的值。这个指令可以在多个上下文中使用,例如 http、server、location 和 if 块中.

# 基本语法
set $variable_name value;
# $variable_name:要设置的变量名,必须以 $ 符号开头
# value:要赋予变量的值,可以是字符串、数字或由其他变量组成的表达式
  • 实例:将域名转换为路径参数

示例目标:

http://username1.testczzj.com/test/userPage1.html 。

——> http://www.testczzj.com/username1/userPage1.html 。

http://username2.testczzj.com/test/userPage2.html 。

——> http://www.testczzj.com/username2/userPage2.html 。

示例文件:

/usr/tmp/username1/userPage1.html 。

/usr/tmp/username2/userPage2.html 。

# hosts 添加配置,注意请将‘服务器IP地址’替换为自己真实的服务器 IP
测试机IP地址 www.testczzj.com
测试机IP地址 username1.testczzj.com
测试机IP地址 username2.testczzj.com
# Linux(编辑:/etc/hosts)(重启命令:/etc/init.d/network restart)
# Windows(编辑:C:\Windows\System32\drivers\etc\hosts)

nginx 配置如下:

server {
    listen       80;
    server_name   www.testczzj.com;
    charset utf-8;

    location /test {
       root /usr/tmp;
       index index.html  index.htm;
       if ( $host ~* ^www.testczzj.com$ ){
            break; # 终止 nginx 在当前请求中的所有后续 location 的匹配
            }
       if ( $host ~* "^(.*)\.testczzj\.com$" ) {
            set $user $1; # 将正则表达式中第一个捕获组的值赋给变量 $user
            rewrite .* http://www.testczzj.com/$user permanent;
            }
    }

    location /username1 {
            alias  /usr/tmp/username1;
            # root /usr/tmp;
            index  userPage1.html index.html  index.htm;
    }

    location /username2 {
            alias /usr/tmp/username2;
            # root /usr/tmp;
            index userPage2.html index.html index.htm;
    }
}

效果如下图:

2.5 return 指令

return 指令是 nginx 配置中用于立即返回指定状态码和可选的响应体的指令。它通常用于处理特定的请求,并立即终止进一步的处理.

# 语法
return code [text];
# code: 要返回的 HTTP 状态码,例如 200, 404, 500 等
# [text]: 可选的响应体文本。如果省略,Nginx 将使用默认的响应体

# 简单示例
location / {
    return 200; # 对所有匹配 / 路径的请求返回 HTTP 200 状态码
}
# 返回状态码和自定义响应体
location /custom {
    return 403 "Access Denied"; # 对所有匹配 /custom 路径的请求返回 HTTP 403 状态码,并在响应体中包含 "Access Denied" 文本
}
# 重定向到另一个 URL
location /redirect {
    return 301 http://example.com; # 将所有匹配 /redirect 路径的请求重定向到 http://example.com,并返回 HTTP 301 状态码
}

return 指令会立即终止当前请求的处理,不会继续执行后续的配置指令。因此,它通常放在 location 块的开头.

如果需要返回带有复杂内容的响应体,建议使用 add_header 和 echo 模块,或者通过内部重定向到一个专门处理这些内容的 location.

  • 实例:若 URL 中有调用 .sh 脚本文件,直接返回 403 拒绝操作

示例目标:

http://www.testczzj.com/test/ 。

——>正常加载指定页面:http://www.testczzj.com/test/test_page.html 。

http://www.testczzj.com/test/ts.sh 。

——> 返回禁止访问:403 Forbidden 。

nginx 配置如下:

server {
    listen       80;
    server_name   www.testczzj.com;
    charset utf-8;

    location ~*  \.sh$ { # 写在最前边
            return  403;
    }
    
    location /test {
            alias  /usr/tmp/test;
            index  test_page.html index.html  index.htm;
    }
}

效果如下图:

  • 实例:http 转 https(端口 80 转 443)

注意,这个测试需要有 SSL 证书.

如下配置项供参考:(未经实际验证) 。

server {
    listen       80;
    server_name  www.testpm.cn;
    access_log  /var/log/nginx/http_access.log  main;
    return 301 https://www.testpm.cn$request_uri;   #返回301永久重定向
}
server {
    listen 443 ssl;
    server_name www.testpm.cn;
    access_log  /var/log/nginx/https_access.log  main;

    #ssl on;
    ssl_certificate   /etc/nginx/cert/2447549_www.testpm.cn.pem;
    ssl_certificate_key  /etc/nginx/cert/2447549_www.testpm.cn.key;
    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers  ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
    ssl_prefer_server_ciphers on;

    location / {
        root  /usr/share/nginx/html;
        index index.html index.htm;
    }
}

可以通过 curl 命令进行检验:

# 使用 curl 命令行工具发送 HTTP 请求的命令
# -I 或 --head 选项告诉 curl 只获取 HTTP 响应的头部信息,而不下载整个内容
# 这对于检查服务器响应头信息非常有用
# 当你运行这个命令时,curl 会向目标服务发送一个 HTTP HEAD 请求,并返回该请求的响应头信息
# 响应头信息通常包括状态码、内容类型、服务器信息、日期等。
[root@localhost ~]# curl -I http://www.testpm.cn
HTTP/1.1 301 Moved Permanently
Server: nginx/1.16.0
Date: Wed, 03 Jul 2019 13:52:30 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: https://www.testpm.cn/

2.6 last(重新进行匹配)、break(终止) 指令

last 和 break 指令是用于控制 rewrite 模块的行为,它们在处理重写规则时有不同的作用.

last 指令在当前的 rewrite 规则执行完后,会停止处理后续的 rewrite 规则,并根据重写后的新 URI 重新发起一次请求,并从服务器配置的顶部开始重新匹配 location 块.

  示例:假设有一个 location 块/old_path,使用rewrite ^/old_path(.*)$ /new_path$1 last;,当访问/old_path/something时,nginx 会将其重写为/new_path/something并重新匹配 location 块.

break 指令在当前的 rewrite 规则匹配成功后,会停止处理后续的 rewrite 规则,但不会重新开始匹配 location 块,即在满足特定条件后终止重写过程.

  示例:同样的 location 块/old_path,如果使用rewrite ^/old_path(.*)$ /new_path$1 break;,当访问/old_path/something时,nginx 会将其重写为/new_path/something,但不会重新匹配 location 块,而是继续处理当前请求的其他阶段.

参考:https://blog.csdn.net/m0_62396418/article/details/135747521 。

最后此篇关于nginx简单实践:静态资源部署、URL重写【nginx实践系列之一】的文章就讲到这里了,如果你想了解更多关于nginx简单实践:静态资源部署、URL重写【nginx实践系列之一】的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

56 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com