Nginx 重写功能与反向代理

1.重写功能

Nginx服务器利用 ngx_http_rewrite_module 模块解析和处理rewrite请求,此功能依靠 PCRE(perl compatible regular expression),因此编译之前要安装PCRE库,rewrite是nginx服务器的重要功能之

一,用于实现URL的重写,URL的重写是非常有用的功能,比如它可以在我们改变网站结构之后,不需要客户端修改原来的书签,也无需其他网站修改我们的链接,就可以设置为访问,另外还可以在一定程度上提高网站的安全性。

1.1 if指令

用于条件匹配判断,并根据条件判断结果选择不同的Nginx配置,可以配置在server或location块中进行配置,Nginx的if语法仅能使用if做单次判断,不支持使用if else或者if elif这样的多重判断,用法如下:

if (条件匹配) { 
 action
}

使用正则表达式对变量进行匹配,匹配成功时if指令认为条件为true,否则认为false,变量与表达式之间使用以下符号链接:

yaml 复制代码
= #比较变量和字符串是否相等,相等时if指令认为该条件为true,反之为false
!=  #比较变量和字符串是否不相等,不相等时if指令认为条件为true,反之为false
~ #区分大小写字符,可以通过正则表达式匹配,满足匹配条件为真,不满足匹配条件为假
!~ #区分大小写字符,判断是否匹配,不满足匹配条件为真,满足匹配条件为假

~* #不区分大小写字符,可以通过正则表达式匹配,满足匹配条件为真,不满足匹配条件为假
!~* #不区分大小字符,判断是否匹配,满足匹配条件为假,不满足匹配条件为真


-f 和 !-f #判断请求的文件是否存在和是否不存在
-d 和 !-d #判断请求的目录是否存在和是否不存在
-x 和 !-x #判断文件是否可执行和是否不可执行
-e 和 !-e #判断请求的文件或目录是否存在和是否不存在(包括文件,目录,软链接)
#注意:
#如果$变量的值为空字符串或0,则if指令认为该条件为false,其他条件为true。
#nginx 1.0.1之前$变量的值如果以0开头的任意字符串会返回false

3字打头重定向
301  永久重定向  将缓存记录在浏览器中
302  临时重定向  没有缓存  每次都要重定向 
304  

1.2 return

return用于完成对请求的处理,并直接向客户端返回响应状态码,比如:可以指定重定向URL(对于特殊重定向状态码,301/302等) 或者是指定提示文本内容(对于特殊状态码403/500等),处于此指令后的所有配置都将不被执行,return可以在server、if 和 location块进行配置

语法格式:

bash 复制代码
www.kgc.com/test/
404
return code; #返回给客户端指定的HTTP状态码
return code [text]; #返回给客户端的状态码及响应报文的实体内容,可以调用变量,其中text如果有空格,需要用单或双引号
return code url; #返回给客户端的URL地址    

范例:

bash 复制代码
例子1;
server { 
    listen 80;
    server_name www.kgc.com;
    root /data/nginx/pc/;
	location /{
        root /data/nginx/pc/;

}
  location /test {      #访问test 直接返回403
	return 403;         #可以改成666    
  }

}
bash 复制代码
例子2;
location /test {
        default_type text/plain;
        return 302 http://www.baidu.com;    
        #这里直接跳转百度(临时重定向)
}

301 缓存在磁盘上,有些
302 没有缓存 , 服务器断开无法重定向

1.3 set 指令

指定key并给其定义一个变量,变量可以调用Nginx内置变量赋值给key,另外set定义格式为set $key value,value可以是text, variables和两者的组合。

bash 复制代码
location /main {
   root /data/nginx/html/pc;
   index index.html;
   default_type text/html;
    set $name kgc;
    #相当于定义了一个新的变量
    echo $name;
    set $my_port $server_port;
    echo $my_port;
}

1.4 break 指令

用于中断当前相同作用域(location)中的其他Nginx配置,与该指令处于同一作用域的Nginx配置中,位于它前面的配置生效,位于后面的 ngx_http_rewrite_module 模块中指令就不再执行,Nginx服务器在根据配置处理请求的过程中遇到该指令的时候,回到上一层作用域继续向下读取配置,该指令可以在server块和locationif块中使用。

注意: 如果break指令在location块中后续指令还会继续执行,只是不执行 ngx_http_rewrite_module 模块的指令,其它指令还会执行。

具体使用:

bash 复制代码
if ($slow) {
   limit_rate 10k;
   break;
}
location /main {
   root /data/nginx/html/pc;
   default_type text/html;
    set $name kgc;
    echo $name;
   break;  
   #location块中break后面指令还会执行
    set $my_port $server_port;
    #这个命令就不会执行了
    echo $my_port;
    #这个命令还会继续执行
 }
 

1.5 rewrite 指令

通过正则表达式的匹配来改变URI,可以同时存在一个或多个指令,按照顺序依次对URI进行匹配,rewrite主要是针对用户请求的URL或者是URI做具体处理

rewrite可以配置在 server、location、if

语法格式

ini 复制代码
rewrite       regex               replacement                [flag];
        正则匹配原始访问url      替代你想让客户访问的              标志

正则表达式格式:

ini 复制代码
. #匹配除换行符以外的任意字符
\w #匹配字母或数字或下划线或汉字
\s #匹配任意的空白符
\d #匹配数字     
\b #匹配单词的开始或结束
^ #匹配字付串的开始
$ #匹配字符串的结束
* #匹配重复零次或更多次
+ #匹配重复一次或更多次
? #匹配重复零次或一次
(n) #匹配重复n次
{n,} #匹配重复n次或更多次
{n,m} #匹配重复n到m次
*? #匹配重复任意次,但尽可能少重复
+? #匹配重复1次或更多次,但尽可能少重复
?? #匹配重复0次或1次,但尽可能少重复
{n,m}? #匹配重复n到m次,但尽可能少重复
{n,}? #匹配重复n次以上,但尽可能少重复
\W  #匹配任意不是字母,数字,下划线,汉字的字符
\S #匹配任意不是空白符的字符
\D #匹配任意非数字的字符
\B #匹配不是单词开头或结束的位置
[^x] #匹配除了x以外的任意字符
[^kgc] #匹配除了kgc 这几个字母以外的任意字符
rewrite flag使用介绍

利用nginx的rewrite的指令,可以实现url的重新跳转,rewrtie有四种不同的flag,分别是redirect(临时重定向302)、permanent(永久重定向301)、break和last。其中前两种是跳转型的flag,后两种是代理型

  • 跳转型指由客户端浏览器重新对新地址进行请求
  • 代理型是在WEB服务器内部实现跳转
ini 复制代码
redirect;302
#临时重定向,重写完成后以临时重定向方式直接返回重写后生成的新URL给客户端,由客户端重新发起请求;使用相对路径,或者http://或https://开头,状态码:302

permanent;301       www.bj.com     www.beijing.com
#重写完成后以永久重定向方式直接返回重写后生成的新URL给客户端,由客户端重新发起请求,状态码:301



break;       www.bj.com
#重写完成后,停止对当前URL在当前location中后续的其它重写操作,而后直接跳转至重写规则配置块之后的其它配置;结束循环,建议在location中使用
#适用于一个URL一次重写 





last;
#重写完成后,停止对当前URI在当前location中后续的其它重写操作,而后对新的URL启动新一轮重写检查,不建议在location中使用
#适用于一个URL多次重写,要注意避免出现超过十次以及URL重写后返回错误的给用户301

具体例子:

bash 复制代码
server  {
   listen  80;
   server_name www.mo.com;
   root /data/nginx/html/mo/;
     location /bj {
    rewrite  ^/bj/(.*)  /beijing/$1 permanent;
    #当访问bj时就直接跳转beijing全程这个文件
}
}
ini 复制代码
http转成https
server  {
   listen  80;
   listen 443 ssl;
   ssl_certificate /opt/www.kgc.com.crt;
   ssl_certificate_key /opt/www.kgc.com.key;
   ssl_session_cache shared:sslcache:20m;
   ssl_session_timeout 10m;
   server_name www.mo.com;
   root /data/nginx/html/mo/;
     location / {
     if ( $scheme = http  ) {
     #必须加上判断不然会陷入死循环
    rewrite / https://192.168.223.100   permanent;
    #只要访问根就会跳转https协议       表示永久定向


}
}
}

1.6 防盗链

防盗链基于客户端携带的referer实现,referer是记录打开一个页面之前记录是从哪个页面跳转过来的标记信息,如果别人只链接了自己网站图片或某个单独的资源,而不是打开了网站的整个页面,这就是盗链,referer就是之前的那个网站域名,正常的referer信息有以下几种:

r 复制代码
none:#请求报文首部没有referer首部,比如用户直接在浏览器输入域名访问web网站,就没有referer信息。
blocked:#请求报文有referer首部,但无有效值,比如为空。
server_names:#referer首部中包含本主机名及即nginx 监听的server_name。
arbitrary_string:#自定义指定字符串,但可使用*作通配符。示例: *.kgc.org www.kgc.*
regular expression:#被指定的正则表达式模式匹配到的字符串,要使用~开头,例如:~.*\.kgc\.com

实现防盗链

ruby 复制代码
location ~* \.(jpg|gif|swf)$ {            
         root  html;
         expires 1d;
         valid_referers none blocked *.kgc.com kgc.com;   
         if ( $invalid_referer ) {
           rewrite ^/ http://www.kgc.com/error.jpg;
           }
        }
        
        
        
~* \.(jpg|gif|swf)$:这段正则表达式表示匹配不区分大小写,以.jpg 或.gif 或.swf 结尾的文件
Valid_referers:设置信任的网站,可以正常使用图片。
None :浏览器中 referer 为空的情况,就是直接在浏览器访问图片。
Blocked :referer 不为空的情况 ,但是值被代理或防火墙删除了,这些值不以 http://或https://开头。
后面的网址或者域名:referer 中包含相关字符串的网址。
If 语句:如果链接的来源域名不在 valid_referers 所列出的列表中,$invalid_referer 为1,则执行后面的操作,即进行重写或返回 403 页面。

具体操作 1.先实行盗链存一张照片

2.到二号机上去写自己的html文件

less 复制代码
<html>
<body>
<h1>this is ky31
<img src="http://192.168.233.100/fengjing.jpg"/>
</body>
</html>

3.输入二号机的地址然后盗链

4.布置盗链文件配置

ruby 复制代码
location ~* \.(jpg|gif|swf)$ {            
         expires 1d;
         valid_referers none blocked *.mo.com mo.com;   
         if ( $invalid_referer ) {
           rewrite ^/ http://www.mo.com/error.jpg;
           }
        }

5.去配置文件下创建一个error.jpg,让他跳转

6.再刷新一下之前的端口号

2.反向代理

反向代理:reverse proxy,指的是代理外网用户的请求到内部的指定的服务器,并将数据返回给用户的一种方式,这是用的比较多的一种方式。

Nginx 除了可以在企业提供高性能的web服务之外,另外还可以将 nginx 本身不具备的请求通过某种预定义的协议转发至其它服务器处理,不同的协议就是Nginx服务器与其他服务器进行通信的一种规范,主要在不同的场景使用以下模块实现不同的功能

bash 复制代码
ngx_http_proxy_module: #将客户端的请求以http协议转发至指定服务器进行处理
ngx_http_upstream_module #用于定义为proxy_pass,fastcgi_pass,uwsgi_pass等指令引用的后
端服务器分组
ngx_stream_proxy_module:#将客户端的请求以tcp协议转发至指定服务器处理
ngx_http_fastcgi_module:#将客户端对php的请求以fastcgi协议转发至指定服务器助理
ngx_http_uwsgi_module: #将客户端对Python的请求以uwsgi协议转发至指定服务器处理

2.1反向代理配置参数

ruby 复制代码
proxy_pass; 
#用来设置将客户端请求转发给的后端服务器的主机,可以是主机名(将转发至后端服务做为主机头首部)、IP
地址:端口的方式
#也可以代理到预先设置的主机群组,需要模块ngx_http_upstream_module支持

#示例:
 location /web {
   index index.html;
   proxy_pass http://10.0.0.18:8080; #8080后面无uri,即无 / 符号,需要将location后面url 附加到proxy_pass指定的url后面,此行为类似于root
#proxy_pass指定的uri不带斜线将访问的/web,等于访问后端服务器
http://10.0.0.18:8080/web/index.html,即后端服务器配置的站点根目录要有web目录才可以被访问
    # http://nginx/web/index.html ==> http://10.0.0.18:8080/web/index.html
    
proxy_pass http://10.0.0.18:8080/;   #8080后面有uri,即有 / 符号,相当于置换,即访问/web时实际返回proxy_pass后面uri内容.此行为类似于alias 
    #proxy_pass指定的uri带斜线,等于访问后端服务器的http://10.0.0.18:8080/index.html 内容返回给客户端
 }  # http://nginx/web/index.html ==> http://10.0.0.18:8080

实例:

ini 复制代码
server  {
   listen  80;
   listen 443 ssl;
 ssl_certificate /opt/www.kgc.com.crt;
 ssl_certificate_key /opt/www.kgc.com.key;
 ssl_session_cache shared:sslcache:20m;
 ssl_session_timeout 10m;
   server_name www.mo.com;
   root /apps/nginx/html;
  location / {
 proxy_pass http://192.168.223.101;
}
}

注意:

所以会去找192.168.223.100/wab,这个网页

置换时前面不能带正则表达式,带正则表达式时后面不能加/

2.2 反向代理中动静分离

实验内容:

实现架构 7-3为客户机 ,7-1为代理服务器,7-2与7-4分别为动态资源与静态资源 做好动静分离。

具体操作:

1.先做好动态文件与动态文件,在4号中做一个api文件

2.去7-1代理服器进行配置

3.先去7-4做个api网页

4.再去7-2做静态页面

5.去测试机7-3进行测试

2.3反向代理的缓存功能

ini 复制代码
proxy_cache zone_name | off; 默认off
#指明调用的缓存,或关闭缓存机制;Context:http, server, location
#zone_name 表示缓存的名称.需要由proxy_cache_path事先定义

proxy_cache_key string;
#缓存中用于"键"的内容,默认值:proxy_cache_key $scheme$proxy_host$request_uri;



proxy_cache_valid [code ...] time;
#定义对特定响应码的响应内容的缓存时长,定义在http{...}中
 示例:
 proxy_cache_valid 200 302 10m;
 proxy_cache_valid 404 1m;
 
 
 #调用缓存功能,需要定义在相应的配置段,如server{...};或者location等
proxy_cache proxycache;
proxy_cache_key $request_uri; #对指定的数据进行MD5的运算做为缓存的key
proxy_cache_valid 200 302 301 10m; #指定的状态码返回的数据缓存多长时间
proxy_cache_valid any 1m;   #除指定的状态码返回的数据以外的缓存多长时间,必须设置,否则不会缓存


先去代理服务器主配置文件http模块中加入配置
proxy_cache_path /data/nginx/proyxcache   levels=1:1:1 keys_zone=proxycache:20m inactive=120s max_size=1g;



再去子配置文件中添加
server {
   listen 80;
   proxy_cache proxycache;
   proxy_cache_key $request_uri;    创建了缓存别名
   #proxy_cache_key $host$uri$is_args$args;    
   proxy_cache_valid 200 302 301 10m;
   proxy_cache_valid any 5m;
   server_name www.kgc.com;
   root /data/nginx/pc;
  location / {
  root /data/nginx/pc;
  }
  location /api {
  proxy_pass http://192.168.91.101:9527;
  }
  location ~* \.(jpg|png|gif|html)$ {
  proxy_pass http://192.168.91.102;
  }

清理缓存:

makefile 复制代码
方法1: rm -rf 缓存目录
方法2: 第三方扩展模块ngx_cache_purge

2.4 实现反向代理客户端ip穿透

ini 复制代码
[root@centos8 ~]# cat /apps/nginx/conf/conf.d/pc.conf
server {
 listen 80;
 server_name www.kgc.org;
 location / {
   index index.html index.php;
   root /data/nginx/html/pc;
   proxy_pass http://10.0.0.18;
    #proxy_set_header X-Real-IP $remote_addr;                   #只添加客户端IP到
请求报文头部,转发至后端服务器
   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #添加客户端IP和反向代理服务器IP到请求报文头部

1.使用http来做下ip穿透,7-3做客户端,7-2作为真实服务器,7-1作为代理服务器

2.再去7-1去做代理服务器

3.这边用我们的7-3客户机测试一下,显示的是真实服务器7-2的内容

4.去修改7-2真实服务器上面的配置实现ip透射

perl 复制代码
[root@centos8 ~]#vim /etc/httpd/conf/httpd.conf
 LogFormat "%{X-Forwarded-For}i %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
 
 197行

5.去7-1我们自己的子配置文件中加上变量,添加客户端IP到 请求报文头部,转发至后端服务器

6.再去7-3客户机访问一下看看日志是否有改动

但是这个只能限于一层代理,能看到客户机的ip地址下面我们要做一个不管几个代理服务器都能看到客户机的ip地址

1.先将7-1代理服务器的日志功能打开

2.我们自己再去7-4再次建立一个反向代理服务器

3.7-1代理机也需要修改

  1. 再去7-2主服务器中修改日志内容

5.再去测试就行了

2.5 反向代理的负载均衡

在上一个节中Nginx可以将客户端的请求转发至单台后端服务器但是无法转发至特定的一组的服务器,而且不能对后端服务器提供相应的服务器状态监测,Nginx 可以基于ngx_http_upstream_module模块提供服务器分组转发、权重分配、状态监测、调度算法等高级功能

2.5.1 轮询

ini 复制代码
#自定义一组服务器,配置在http块内
upstream   web { 
 server 192.168.91.100    调度算法
 server 192.168.91.101
}

location  / {
pass_proxy  http://web/
}


#示例
upstream backend {
   server backend1.example.com weight=5;     权重
   server 127.0.0.1:8080       max_fails=3  fail_timeout=30s;
   server unix:/tmp/backend3;
   server backup1.example.com backup;
}

具体操作:

  1. 7-4中写一个配置文件
  1. 7-1也把文件内容改下

3.去代理服器7-3中修改主配置文件

4.再修改7-3中的子配置文件

5.使用别的机器去测试,访问的是7-3的ip地址查看是否轮询跳转

2.5.2 加权轮询

权重方式,在轮询策略的基础上指定轮询的比例。

一般来说,性能好的服务器权重大,性能差的权重给小一些。

weight=number #设置权重,默认为1,实现类似于LVS中的WRR,WLC等

具体的操作:

1.在代理服务器中主配置文件中夹weight

2.使用其他主机上测试一下

2.5.3 备份服务器

backup #设置为备份服务器,当所有后端服务器不可用时,才会启用此备用服务器 sorry server 自己不能转自己

具体操作:

1.现在7-3代理服务器中添加备份服务器

2.再到7-2中写我们的备份服务器内容

3.关闭另外两台服务器,开始测试自己的备用服务器

2.5.4 最小连接数

把请求转发给连接数较少的后端服务器。轮询算法是把请求平均的转发给各个后端,使它们的负载大致相同;但是,有些请求占用的时间很长,会导致其所在的后端负载较高。这种情况下,least_conn这种方式就可以达到更好的负载均衡效果。

对比后端web(真实服务器),谁接待的连接数最少,优先将新来的链接数交给最少得服务器

ini 复制代码
upstream web_test { 
      least_conn;  --把请求转发给连接数较少的后端服务器
      server 10.10.2.100:80; weight=1;
      server 10.10.3.100:80; weight=2;
}

2.5.5 fair

此种算法可以依据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间来分配请求,响应时间短的优先分配。需要自己下载安装fair模块

ini 复制代码
upstream web_test { 
      server 10.10.2.100:80; weight=1;
      server 10.10.3.100:80; weight=2;
      fair;  --实现响应时间短的优先分配
}

2.5.6 hash

ip hash

命令:md5sum 加文件名

相当于hash掉文件,出来的值是一直跟着文件的,不会改变,除非你去往文件里加东西,hash值会改变

通过ip hash 值是不会变的所以可以保持连接

每个请求按访问IP的hash结果分配,同一个IP客户端固定访问一个后端服务器。可以保证来自同一ip的请求被打到固定的机器上,可以解决session问题。

ini 复制代码
upstream web_test { 
      ip_hash;  --同一个IP客户端固定访问一个后端服务器
      server 10.10.2.100:80; weight=1;
      server 10.10.3.100:80; weight=2;
}
url_hash

按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器。一旦缓存住了资源,再次收到请求,就可以从缓存中读取。

ini 复制代码
upstream web_test { 
      hash $request_uri;  --实现每个url定向到同一个后端服务器
      server 10.10.2.100:80; weight=1;
      server 10.10.3.100:80; weight=2;
}
相关推荐
啥都想学的又啥都不会的研究生1 分钟前
高性能MySQL-查询性能优化
数据库·笔记·学习·mysql·面试·性能优化
m0_7482561442 分钟前
前端图表与数据可视化 - 2024 年实战与面试重点
前端·信息可视化·面试
卷心菜是俺2 小时前
JVM和数据库面试知识点
jvm·数据库·面试
Marx82013 小时前
英语尬面后,我做了一个生成英语学习视频的小工具
前端·面试·产品
Oneforlove_twoforjob3 小时前
【Java基础面试题026】Java中的String、StringBuffer和StringBuilder的区别是什么?
java·开发语言·面试
上海运维Q先生9 小时前
面试题整理9----谈谈对k8s的理解2
云原生·面试·kubernetes
程序员清风15 小时前
阿里面试题:MySQL为什么要改进LRU算法?
数据库·后端·面试
小蜗牛慢慢爬行15 小时前
Java8 Stream编码问题
java·开发语言·后端·面试
快乐点吧17 小时前
【前端面试】三次握手/http/https,是否跳转携带cookie,跨域
前端·http·面试
陈大鱼头20 小时前
写在裸辞 5 个月之后的年终总结
前端·面试·github