- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
本文为 nginx 简单实践系列文章之一,主要简单实践了两个内容:静态资源部署、重写,仅供参考.
关于 Nginx 基础,以及安装和配置详解,可以参考博主过往文章:
https://www.cnblogs.com/hnzhengfy/p/Nginx.html 。
当前项目的结构基本上都是前后端分离,前端的相关资源,如 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 。
rewrite 就是 URL 重写,是一个将传入的 web 重定向到其他 URL 的过程.
上一部分静态资源部署,主要用的是 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 路径进行匹配,一旦匹配成功,就会执行对应的处理逻辑.
Rewrite 相关指令有 if、rewrite、set、return.
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 请求到达的服务器端口号
后文将进行示例演示.
Nginx 中的 rewrite 指令可以包含一个可选的 flag(标志),用于控制重写操作后的行为.
这个 flag 的类型总共有四种,如下:
注意:可以使用测试域名,但前提是要修改 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;
}
}
}
自动跳转:
示例目标: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 后路径没有资源,因此页面会加载失败) 。
示例目标: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;
}
}
}
自动补上斜线:
示例目标: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;
}
}
如下图自动跳转:
示例目标: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;
}
}
如下图自动跳转:
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;
}
}
效果如下图:
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.
示例目标:
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;
}
}
效果如下图:
注意,这个测试需要有 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/
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的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
本文分享自华为云社区《大模型LLM之分布式训练》,作者: 码上开花_Lancer。 随着语言模型参数量和所需训练数据量的急速增长,单个机器上有限的资源已无法满足大语言模型训练的要求。需要设计分布式训
本文分享自华为云社区《五大基础算法--动态规划法》,作者: 大金(内蒙的)。 一、基本概念 动态规划法,和分治法极其相似。区别就是,在求解子问题时,会保存该子问题的解,后面的子问题求解时,可以直接拿来
pip install scp pip install pexpect 测试代码: import os import stat import paramiko # 用于调用scp命令 def s
我目前正在实现“ token ”REST 服务。 token 只是一个字符串,由一些参数构建而成,然后经过哈希处理并在一定时间后过期。 我想在我的 REST 服务中有一个可以验证 token 的端点,
打开软删除后,我在客户端上添加一条记录,推送,删除添加的记录推送,然后尝试使用与初始记录相同的主键添加新记录(然后推送),我得到一个异常(exception)。 EntityDomainManager
打开软删除后,我在客户端上添加一条记录,推送,删除添加的记录推送,然后尝试使用与初始记录相同的主键添加新记录(然后推送),我得到一个异常(exception)。 EntityDomainManager
我有一个应用程序,每 x 秒接收一次天气信息。我想将此数据保存到 XML 文件中。 我应该为每个天气通知创建一个新的 XML 文件,还是将每个通知附加到同一个 XML 文件中?我不确定 XML 标准的
我猜我们大多数人都必须在某个时候处理这个问题,所以我想我会问这个问题。 当您的 BLL 中有很多集合并且您发现自己一遍又一遍地编写相同的旧内联(匿名)谓词时,显然有必要进行封装,但实现封装的最佳方
我有一些 c# 代码已经运行了一段时间了..我不得不说,虽然我了解 OO 原则的基础知识,但显然有不止一种方法可以给猫剥皮(尽管我讨厌那个短语!)。 因此,我有一个基本抽象类作为基本数据服务类,如下所
我设计了一个 SQL 数据库系统(使用 Postgre),我有一个问题,即创建一个关系/引用的常见做法是什么,这种关系/引用即使在引用的对象被删除时也能持续存在。 比如有一个UserORM,还有Act
我们的目标是搜索用户输入的字符串并计算在其中找到多少元音。不幸的是我被困在这里,有什么帮助吗? def numVowels(s): vowels= "AEIOUaeiou" if s
我有一个适用于我的“items”int 数组的旋转函数。下面的代码完成了它,除了我不必要地传输值。我正在努力实现“就地”轮换。我的意思是 ptrs 会递增或递减,而不是从数组中获取值。我需要通过这种方
我有一个 json 存储在我的应用程序文档文件夹中,我需要在我的所有 View 中使用它。我正在加载 json 并将其添加到每个 View 中的 NSMutableArray。但现在我了解到,我可以将
我用 C++ 开始了一个项目。这种语言的内存管理对我来说是新的。 我过去常常使用 new () 创建对象,然后传递指针,虽然它可以工作,但调试起来很痛苦,人们看到代码时会用有趣的眼神看着我。我为它没有
已结束。 这个问题是 off-topic .它目前不接受答案。 想要改进这个问题? Update the question所以它是on-topic堆栈溢出。 关闭 10 年前。 Improve thi
保持类松散耦合是编写易于理解、修改和调试的代码的一个重要方面——我明白这一点。然而,作为一个新手,几乎任何时候我都会超越我所苦苦挣扎的最简单的例子。 我或多或少地了解如何将字符串、整数和简单数据类型封
我发现我需要编写大量重复代码,因为我无法从其他 Controller 调用函数。例如,这里新闻提要内容在我的代码中重复,我对一个 Controller 做一些特定的事情,然后需要像这样加载我的新闻提要
假设需要一种数字数据类型,其允许值在指定范围内。更具体地说,假设要定义一个整数类型,其最小值为0,最大值为5000。这种情况在很多情况下都会出现,例如在对数据库数据类型,XSD数据类型进行建模时。 在
假设我想循环整个数组来访问每个元素。使用 for 循环、for...in 循环或 for...of 循环是 JavaScript 开发人员的标准做法吗? 例如: var myArray = ["app
我有一个旧的 SL4/ria 应用程序,我希望用 Breeze 取代它。我有一个关于内存使用和缓存的问题。我的应用程序加载工作列表(一个典型的用户可以访问大约 1,000 个这些工作)。此外,还有很多
我是一名优秀的程序员,十分优秀!