一、正向代理和反向代理

正向代理举例:翻越万里长城去游览墙外的景色

反向代理举例:负载均衡

正向代理和反向代理涉及三个主体:

  • 请求方
  • 代理
  • 被请求方

正向代理中,代理跟请求方是一家子,请求方说要啥,代理就给他啥。

反向代理中,代理跟被请求方是一家子,代理统筹规划让哪一个被请求方来处理请求,对于请求方来说,代理就是处理请求的人。大多数情况下,反向代理和被请求方在同一个服务器上。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 基础及实例

最新文章

  1. 利用密钥通过ssh互访
  2. 在JQ中关于this
  3. php5.3 appache phpstudy win7win8win10下 运行速度慢解决办法
  4. ol,ul,dl,table标签的基本语法
  5. [转载] C++11中的右值引用
  6. Oracle把两个空格以上的空格,替换为两个空格
  7. python(5)-正则表达式
  8. pycharm的用法
  9. 算法: 整数中1出现的次数(从1到n整数中1出现的次数)
  10. google 谷歌地图
  11. CSS快速入门-组合选择器
  12. python中操作mysql
  13. TurboLinux11system&#187;adjtimex简介
  14. js实现删除弹框确认
  15. Linux下为Eclipse安装hadoop插件
  16. WAKE-WIN10-SOFT-MATio
  17. DAY16-Django之MTV
  18. 配置OpenResty支持SSL(不受信任的证书)
  19. 文件的特殊权限(SUID,SGID,SBIT)
  20. HDU 3150 Robot Roll Call – Cambot…Servo…Gypsy…Croooow(map)

热门文章

  1. 定义和使用EL函数
  2. OpenCV学习(37) 人脸识别(2)
  3. 三个和数组有关的程序题目(C++)
  4. Cesium随笔(2)加载天地图地图服务【转】
  5. Cisco KVM Console无法打开
  6. Longest Substring Without Repeating Characters leetcode java
  7. Prototype 原型模式 复制 浅拷贝 clone MD
  8. [置顶] Android异步加载数据库和多线程编程
  9. JSP的页面连接和提交方式(web基础学习笔记六)
  10. java之八大排序