一、正向代理和反向代理
正向代理举例:翻越万里长城去游览墙外的景色
反向代理举例:负载均衡
正向代理和反向代理涉及三个主体:
- 请求方
- 代理
- 被请求方
正向代理中,代理跟请求方是一家子,请求方说要啥,代理就给他啥。
反向代理中,代理跟被请求方是一家子,代理统筹规划让哪一个被请求方来处理请求,对于请求方来说,代理就是处理请求的人。大多数情况下,反向代理和被请求方在同一个服务器上。Nginx就是最常用的反向代理服务器。
这里也提一下:动态代理和静态代理
正向代理和反向代理是代理服务器的两种类型
动态代理和静态代理是Java中的设计模式:代理模式。
Spring的两大核心:
- IOC控制反转依赖注入
- AOP面向切面编程
面向切面编程中大量使用动态代理,在每一个方法调用前、调用后、抛异常时进行处理,跟装饰器模式很像。
二、nginx配置体系
nginx主要配置位于/etc/nginx目录下,nginx不仅仅可以用于负载均衡HTTP请求,也可以用于基于TCP的其它协议的负载均衡。/etc/nginx/nginx.conf是nginx的跟配置,一切配置都是这个配置的子孙。
/etc/nginx/nginx.conf
users www-data;定义当前用户 worker_prosesses 4;定义worker数 pid /run/nginx.pid;定义pid文件 events{......} http{... http协议的相关配置 include xxx路径下的conf.d/*.conf; 可以使用文件通配符来描述文件,但是一定是文件而非文件夹 } mail{ ....mail相关的一些配置 server{ listen localhost:xx; protocol pop3; proxy on; } server{ listen localhost:xxxx; protocol imap; proxy on; } }
可以发现,最外层是协议,协议内部有若干个server组成,每个server监听一个端口,根据路径可以转发到本地的其它端口进行处理。include是简单的复制粘贴。
三、用Nginx反向代理Tomcat服务器和Gunicorn服务器
需求说明:Tomcat和Gunicorn分别运行在8080端口和8000端口,现在要让它们共用80端口。
当使用:localhost/tomcat/myapp
时,相当于localhost:8080/myapp
当使用:localhost/gunicorn/myapp
时,相当于localhost:8000/myapp
server { listen 80; server_name www.haha.com; access_log /var/log/nginx/reverse.log; location /tomcat { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /gunicorn { proxy_pass http://127.0.0.1:8000/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
server_name描述了服务器地址部分,既可以是域名,也可以是IP地址。这一项不可省略。
设置proxy_set_header部分是将请求者的真实信息告知后台服务器
需要注意的是:
- 配置nginx时,每一句后面都带有一个分号,不带分号会出错,这是conf文件的语法;
- 配置proxy_pass时,只能精确到端口号,不能转发到再下一级,比如
proxy_pass http://127.0.0.1:8000/myweb/
这样是错误的; - 配置proxy_pass时,端口号后面必须加上反斜杠
/
,否则路径拼接时会因为少一个反斜杠而无法解析,导致404错误。
四、了解负载均衡
负载均衡必然要用到反向代理,让Nginx作为大管家凌驾于处理请求的服务器之上,Nginx可以动态决定让哪个服务器来处理请求。负载均衡问题源远流长:两台相同的处理机处理若干任务,怎么处理能够使得任务尽早完成?这是“双塔”问题;两台不同的处理机处理若干任务,不同处理机处理不同任务花费时间不同,怎样分配任务才能使得任务尽早完成?
负载均衡的核心问题就是:建立用户请求和服务器之间的映射。有如下几种方式:
- 轮询
server=counter++%server_size
用于后台服务器性能差不多的情况 - 轮盘赌
每个服务器有一个权重weight,表示选中这个服务器作为请求处理者的概率。
用于后台服务器性能有差异的情况 - IP-Hash
建立用户IP地址和后台服务器之间的映射表。
用于解决Session问题,避免了Session共享带来的IO压力。 - URL-Hash
建立用户请求URL和后台服务器之间的映射表。
用于解决服务器缓存分布分散,让某个服务器专门负责某类请求,这样能够更专业地处理请求。
这种方式其实就相当于新建了一个Web程序,这时Nginx的作用更像是正向代理而不是反向代理。 - Fair:按照响应时间
Nginx知道每个后端服务器处理请求的时间,谁处理时间短就让谁来处理请求。
在轮盘赌方法中,需要明确知道各个后台服务器的性能好坏。使用Fair方法可以自动检测出后台服务器性能好坏,从而动态分配。
轮盘赌的方式进行如下配置,首先定义一个upstream,它是多个server的集合。然后在location中就可以直接使用这个upstream。
upstream your_host_or_ip { server 127.0.0.3:8000 weight=5; server 127.0.0.3:8001 weight=5; server 192.168.0.1:8000; server 192.168.0.1:8001; } server { listen 80; server_name your_host_or_ip; access_log /var/log/nginx/my_access.log main; location / { proxy_pass http://your_host_or_ip; } }
需要注意的是,一台服务器有两种访问方式:ip地址和域名方式。ip地址方式肯定只能有一种方式进行访问,因为ip地址是全网唯一的。而一台服务器可以绑定多个域名,这样就可以通过多个域名访问同一个服务器了。
当配置了upstream之后,upstream的名称肯定跟服务器的名称(IP或者域名)相同,所以一个域名只能进行一个负载均衡,一个IP也只能进行一个负载均衡,而一台服务器可以进行多个负载均衡。
五、地址匹配
location配置:
直接写一个字符串,常规字符串匹配~
表示执行一个正则匹配,区分大小写~*
表示执行一个正则匹配,不区分大小写^~
表示普通字符匹配。使用前缀匹配。如果匹配成功,则不再匹配其他location。=
进行普通字符精确匹配。也就是完全匹配。
location配置的优先级:
在Nginx的location和配置中location的顺序没有太大关系。正location表达式的类型有关。相同类型的表达式,字符串长的会优先匹配。
以下是按优先级排列说明:
第一优先级:等号类型(=)的优先级最高。一旦匹配成功,则不再查找其他匹配项。
第二优先级:^~
类型表达式。一旦匹配成功,则不再查找其他匹配项。
第三优先级:正则表达式类型(~
~*
)的优先级次之。如果有多个location的正则能匹配的话,则使用正则表达式最长的那个。
第四优先级:常规字符串匹配类型。按前缀匹配。
下面示例一下四种地址类型:
location = / { # 仅仅匹配请求 / [ configuration A ] } location / { # 匹配所有以 / 开头的请求。但是如果有更长的同类型的表达式,则选择更长的表达式。如果有正则表达式可以匹配,则优先匹配正则表达式。 [ configuration B ] } location /documents/ { # 匹配所有以 /documents/ 开头的请求。但是如果有更长的同类型的表达式,则选择更长的表达式。 #如果有正则表达式可以匹配,则优先匹配正则表达式。 [ configuration C ] } location ^~ /images/ { # 匹配所有以 /images/ 开头的表达式,如果匹配成功,则停止匹配查找。所以,即便有符合的正则表达式location,也 # 不会被使用 [ configuration D ] } location ~* \.(gif|jpg|jpeg)$ { # 匹配所有以 gif jpg jpeg结尾的请求。但是 以 /images/开头的请求,将使用 Configuration D [ configuration E ] }
请求匹配实例:
/ -> configuration A /index.html -> configuration B /documents/document.html -> configuration C /images/1.gif -> configuration D /documents/1.jpg -> configuration E
应用举例:隐藏内在的地址
server { # 用 xxoo_admin 来掩饰 admin location / { # 使用break拿一旦匹配成功则忽略后续location rewrite /xxoo_admin /admin break; } # 访问真实地址直接报没权限 location /admin { return 403; } }
六、重写
Nginx的反向代理像一个URL函数,输入是一个URL,输出也是一个URL。运行过程可能是这样的:
用户发起请求url0 url1=f(url0) url2=f(url1) ...直到url不再被重写,被路由到合适的请求处理结点
语法
在配置文件的server块中写,如:
server { rewrite 规则 定向路径 重写类型; }
- 规则:可以是字符串或者正则来表示想匹配的目标url
- 定向路径:表示匹配到规则后要定向的路径,如果规则里有正则,则可以使用
$index
来表示正则里的捕获分组 - 重写类型:
- last :浏览器地址栏URL地址不变,本条规则完成后,会对重写后的URL进行重新匹配。
- break:浏览器地址栏URL地址不变。本条规则匹配完成后,终止匹配,不再匹配后面的规则,
- redirect:返回302临时重定向,浏览器地址会显示跳转后的URL地址
- permanent:返回301永久重定向,浏览器地址栏会显示跳转后的URL地址
需要注意:
- 重写表达式只对相对路径有效。如果想配对主机名,应该使用if语句。
- rewrite只是会改写路径部分的东东,不会改动用户的输入参数,因此这里的if规则里面,你无需关心用户在浏览器里输入的参数,rewrite后会自动添加的
下面举例说明4种重写类型
server { # 访问 /last.html 的时候,页面内容重写到 /index.html 中 rewrite /last.html /index.html last; # 访问 /break.html 的时候,页面内容重写到 /index.html 中,并停止后续的匹配 rewrite /break.html /index.html break; # 访问 /redirect.html 的时候,页面直接302定向到 /index.html中 rewrite /redirect.html /index.html redirect; # 访问 /permanent.html 的时候,页面直接301定向到 /index.html中 rewrite /permanent.html /index.html permanent; # 把 /html/*.html => /post/*.html ,301定向 rewrite ^/html/(.+?).html$ /post/$1.html permanent; # 把 /search/key => /search.html?keyword=key rewrite ^/search\/([^\/]+?)(\/|$) /search.html?keyword=$1 permanent; }
七、Nginx内置的全局变量
在/etc/nginx/fastcgi.conf中可以看到全部定义。
$args :这个变量等于请求行中的参数,同$query_string $content_length : 请求头中的Content-length字段。 $content_type : 请求头中的Content-Type字段。 $document_root : 当前请求在root指令中指定的值。 $host : 请求主机头字段,否则为服务器名称。 $http_user_agent : 客户端agent信息 $http_cookie : 客户端cookie信息 $limit_rate : 这个变量可以限制连接速率。 $request_method : 客户端请求的动作,通常为GET或POST。 $remote_addr : 客户端的IP地址。 $remote_port : 客户端的端口。 $remote_user : 已经经过Auth Basic Module验证的用户名。 $request_filename : 当前请求的文件路径,由root或alias指令与URI请求生成。 $scheme : HTTP方法(如http,https)。 $server_protocol : 请求使用的协议,通常是HTTP/1.0或HTTP/1.1。 $server_addr : 服务器地址,在完成一次系统调用后可以确定这个值。 $server_name : 服务器名称。 $server_port : 请求到达服务器的端口号。 $request_uri : 包含请求参数的原始URI,不包含主机名,如:”/foo/bar.php?arg=baz”。 $uri : 不带请求参数的当前URI,$uri不包含主机名,如”/foo/bar.html”。 $document_uri : 与$uri相同。
如:
访问链接是:http://localhost:88/test1/test2/test.php
网站路径是:/var/www/html
$host:localhost $server_port:88 $request_uri:http://localhost:88/test1/test2/test.php $document_uri:/test1/test2/test.php $document_root:/var/www/html $request_filename:/var/www/html/test1/test2/test.php
八、使用if语句
if (表达式) { }
表达式的写法有很多:
- 当表达式只是一个变量时,如果值为空或任何以0开头的字符串都会当做false
- 直接比较变量和内容时,使用=或!=
- ~正则表达式匹配,
~*
不区分大小写的匹配,!~区分大小写的不匹配
表达式中可以使用shell常用运算符:
- -f和!-f用来判断是否存在文件
- -d和!-d用来判断是否存在目录
- -e和!-e用来判断是否存在文件或目录
- -x和!-x用来判断文件是否可执行
下面看几个if语句的例子:
例子一:简单的if语句
# 如果文件不存在则返回400 if (!-f $request_filename) { return 400; } # 如果host不是xuexb.com,则301到xuexb.com中 if ( $host != 'xuexb.com' ){ rewrite ^/(.*)$ https://xuexb.com/$1 permanent; } # 如果请求类型不是POST则返回405 if ($request_method = POST) { return 405; } # 如果参数中有 a=1 则301到指定域名 if ($args ~ a=1) { rewrite ^ http://example.com/ permanent; }
例子二:在重写中使用if语句
# 访问 /test.html 时 location = /test.html { # 默认值为xiaowu set $name xiaowu; # 如果参数中有 name=xx 则使用该值 if ($args ~* name=(\w+?)(&|$)) { set $name $1; } # 301 rewrite ^ /$name.html permanent; }
举例说明运行结果:
/test.html => /xiaowu.html /test.html?name=ok => /ok.html?name=ok
九、常用命令
service nginx configtest 用来检测配置是否正确
service nginx reload 重新加载配置
使用sudo service nginx
命令可以查看可用参数.
十、root和alias
root
location /request_path/image/ { root /local_path/image/; }
这样配置的结果就是当客户端请求 /request_path/image/cat.png 的时候,
Nginx把请求映射为/local_path/image/request_path/image/cat.png
alias
location /request_path/image/ { alias /local_path/image/; }
这时候,当客户端请求 /request_path/image/cat.png 的时候,
Nginx把请求映射为/local_path/image/cat.png
下面举一个例子,当访问myip/poem/authorImage/libai.jpg的时候会自动去文件夹/home/USER_NAME/authorImage/下去寻找libai.jpg。
location /poem/authorImage/ { alias /home/USER_NAME/authorImage/; autoindex on; }
需要注意的是,必须保证authorImage这个文件夹权限足够,否则Nginx没有权力访问这个文件夹。最简单但是不够安全的方式就是把/etc/nginx.conf文件开头的user www-data改为user root,这样把管理员权限赋予Nginx,Nginx就能够访问任意文件了。这样做的缺点就是,一旦Nginx被攻破,整个系统的文件资源可能都会受到威胁。
十一、例子集合
1、访问http://IP:端口/myf_test/in_ftp/ftp/space_1/111.jpg
实际访问/var/ftp/in_ftp/ftp/space_1/111.jpg
location /myf_test/ { root /; rewrite ^/myf_test/(.*)$ /var/ftp/$1 break; }
2、把www.ikscher.com/index.PHP?route=product/product&product_id=123
重定向到
www.ikscher.com/product/product&product_id=123
if ($request_uri ~* "(.*)index\.php\?route=(.*)"){ set $host_ $1; set $last_ $2; rewrite (.*) $host_$last_? permanent; #这里的.*代表的是url的原先地址,即要转向的url地址。 }
注意:
- 这段规则直接下到server里面,if后面必须有空格,否则报语法错误。
正则表达式的 点和问号都需要\斜杠转义。 - nginx的问号处理,假如现在我要重定向到
www.ikscher.com/?route=product/product&product_id=123
,nginx在进行rewrite的正则表达式中只会将url中?前面的部分拿出来匹配,匹配完成后,?后面的内容将自动追加到url中(包含?),如果不让后面的内容追加上去,请在最后加上?即可。如果想要?后面的内容时请使用$query_string
在这里提醒一点,调试的时候在rewrite的最后一个配置项中不要使用break last这些,使用redirect可以看到转换后的地址。综合以上几点,使用的配置项为
rewrite (.)index.php(.) $1$query_string? permanent;
3、多目录转成参数
要求:abc.domian.com/sort/2 => abc.domian.com/index.PHP?act=sort&name=abc&id=2
规则配置:
if ($host ~* (.*)\.domain\.com) { set $sub_name $1; rewrite ^/sort\/(\d+)\/?$ /index.php?act=sort&cid=$sub_name&id=$1 last; }
4、目录对换
要求:/123456/xxxx -> /xxxx?id=123456
规则配置:rewrite ^/(\d+)/(.+)/ /$2?id=$1 last;
5、特殊浏览器特殊处理
设定nginx在用户使用ie的使用重定向到/nginx-ie目录
规则如下:
if ($http_user_agent ~ MSIE) { rewrite ^(.*)$ /nginx-ie/$1 break; }
6、请求目录自动加/
目录自动加“/” ,这个功能一般浏览器自动完成
if (-d $request_filename){ rewrite ^/(.*)([^/])$ http://$host/$1$2/ permanent; }
7、禁止某些URL
禁止多个目录 location ~ ^/(cron|templates)/ { deny all; break; } 禁止以/data开头的文件,可以禁止/data/下多级目录下.log.txt等请求 location ~ ^/data { deny all; } 禁止单个文件 location ~ /data/sql/data.sql { deny all; }
8、让浏览器缓存静态数据,避免频繁请求静态数据
给favicon.ico和robots.txt设置过期时间; 这里为favicon.ico为99天,robots.txt为7天并不记录404错误日志
location ~(favicon.ico) { log_not_found off; expires 99d; break; } location ~(robots.txt) { log_not_found off; expires 7d; break; }
设定某个文件的浏览器缓存过期时间;这里为600秒,并不记录访问日志
location ^~ /html/scripts/loadhead_1.js { access_log off; expires 600; break; }
Nginx还可以自定义某一类型的文件的保质期时间,具体写法看下文的代码:
location ~* \.(js|css|jpg|jpeg|gif|png|swf)$ { if (-f $request_filename) { expires 1h; break; } } //上段代码就将js|css|jpg|jpeg|gif|png|swf这类文件的保质期设置为一小时。
9、防盗链的设置
防盗链:如果你的网站是个下载网站,下载步骤应该是先经过你的主页找到下载地址,才能下载,为了防止某些网友直接访问下载地址完全不通过主页下载,我们就可以使用防盗链的方式,具体代码如下:
location ~* \.(gif|jpg|swf)$ { valid_referers none blocked start.igrow.cn sta.igrow.cn; if ($invalid_referer) { rewrite ^/ http://$host/logo.png; } }
文件反盗链并设置过期时间
--<盗链多次请求也会打开你的站点的图片啊,所以设置下缓存时间,不会每次盗链都请求并下载这张图片> location ~* ^.+\.(jpg|jpeg|gif|png|swf|rar|zip|css|js)$ { valid_referers none blocked *.jjonline.cn *.jjonline.com.cn *.lanwei.org *.jjonline.org localhost 42.121.107.189; if ($invalid_referer) { rewrite ^/ http://img.jjonline.cn/forbid.gif; return 417; break; } access_log off; break; }
说明:
这里的return 417为自定义的http状态码,默认为403,方便通过nginx的log文件找出正确的盗链的请求地址rewrite ^/ http://img.jjonline.cn/forbid.gif;
显示一张防盗链图片
“access_log off;”不记录访问日志,减轻压力
“expires 3d”所有文件3天的浏览器缓存
10、只允许固定ip访问网站,并加上密码;这个对有权限认证的应用比较在行
location \ { allow 22.27.164.25; #允许的ipd deny all; auth_basic “KEY”; #认证的一些设置 auth_basic_user_file htpasswd; }
11、文件和目录不存在的时重定向
if (!-e $request_filename) { #proxy_pass http://127.0.0.1; #这里是跳转到代理ip,这个代理ip上有一个监听的web服务器 rewrite ^/ http://www.jjonline.cn/none.html; #跳转到这个网页去 #return 404; #直接返回404码,然后会寻找root指定的404.html文件 }
12、域名跳转
域名跳转
server { listen 80; server_name jump.jjonline.cn ;#需要跳转的多级域名 index index.html index.htm index.php; #入口索引文件的名字 root /var/www/public_html/; #这个站点的根目录 rewrite ^/ http://www.jjonline.cn/; #rewrite到这个地址,功能表现:在浏览器上输入jump.jjonline.cn并回车,不会有任何提示直接变成www.jjonline.cn access_log off; }
多域名转向
server { listen 80; server_name www.jjonline.cn www.jjonline.org; index index.html index.htm index.php; root /var/www/public_html/; if ($host ~ “jjonline\.org”) { rewrite ^(.*) http://www.jjonline.cn$1 permanent; } }
三级域名跳转
if ($http_host ~* “^(.*)\.i\.jjonline\.cn$”) { rewrite ^(.*) http://demo.jjonline.cn$1; break; }
13、域名镜像
server { listen 80; server_name mirror.jjonline.cn; index index.html index.htm index.php; root /var/www/public_html; rewrite ^/(.*) http://www.jjonline.cn/$1 last; access_log off; }
十二、Nginx的其他功能
- 压缩
使用gzip压缩的方式来传递HTML文件能够减少传输量。 - 缓存
对于常用的请求,可以设置缓存时间。
最后、参考资料
java静态代理和动态代理
Nginx location在配置中的优先级
nginx配置url重写
nginx 重写 rewrite 基础及实例
来源:https://www.cnblogs.com/weiyinfu/p/6857425.html