Nginx反向代理

参考资源:

Nginx 从听说到学会

Mac Nginx 安装(Brew)

用 nginx 的反向代理机制解决前端跨域问题

什么是 Nginx

==Nginx== 是一款轻量级的 ==Web== 服务器/反向代理服务器及电子邮件 ==(IMAP/POP3)== 代理服务器,并在一个 ==BSD-like == 协议下发行。
其特点是占有内存少,并发能力强,事实上 ==nginx== 的并发能力确实在同类型的网页服务器中表现较好,中国大陆使用 ==nginx== 网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。
——百度词条

  • Nginx 使用基于事件驱动架构,使得其可以支持数以百万级别的 TCP 连接

  • 高度的模块化和自由软件许可证是的第三方模块层出不穷

  • Nginx 是一个跨平台服务器,可以运行在 Linux, FreeBSD, Solaris, AIX, Mac OS, Windows 等操作系统上

  • 这些优秀的设计带来的极大的稳定性。

Web 服务器

lighttpd

Lighttpd 是一个具有非常低的内存开销,cpu 占用率低,效能好,以及丰富的模块等特点。lighttpd 是众多 OpenSource 轻量级的 web
server 中较为优秀的一个。支持 FastCGI, CGI, Auth, 输出压缩(output compress), URL 重写,
Alias 等重要功能。

Lighttpd 使用 fastcgi 方式运行 PHP,它会使用很少的 PHP 进程响应很大的并发量。

Fastcgi 的优点在于:

  • 从稳定性上看, fastcgi 是以独立的进程池运行来 cgi,单独一个进程死掉,系统可以很轻易的丢弃,然后重新分配新的进程来运行逻辑.
  • 从安全性上看, fastcgi 和宿主的 server 完全独立, fastcgi 怎么 down 也不会把 server 搞垮,
  • 从性能上看, fastcgi 把动态逻辑的处理从 server 中分离出来, 大负荷的 IO 处理还是留给宿主 server, 这样宿主 server 可以一心一意作 IO,对于一个普通的动态网页来说, 逻辑处理可能只有一小部分,
    大量的图片等静态 IO 处理完全不需要逻辑程序的参与
  • 从扩展性上讲, fastcgi 是一个中立的技术标准, 完全可以支持任何语言写的处理程序 php,Java,Python

Apache

apache 是世界排名第一的 web 服务器, 根据 netcraft 所作的调查,世界上百分之五十以上的 web 服务器在使用 apache.

1995 年 4 月, 最早的 apache(0.6.2 版)由 apache group 公布发行. apache group
是一个完全通过 internet 进行运作的非盈利机构, 由它来决定 apache web 服务器的标准发行版中应该包含哪些内容.
准许任何人修改隐错, 提供新的特征和将它移植到新的平台上, 以及其它的工作. 当新的代码被提交给 apache group 时,
该团体审核它的具体内容, 进行测试 如果认为满意, 该代码就会被集成到 apache 的主要发行版中。

apache 的特性:

几乎可以运行在所有的计算机平台上
支持最新的 http/1.1 协议 简单而且强有力的基于文件的配置(httpd.conf)
支持通用网关接口(cgi)
支持虚拟主机
支持 http 认证
集成 perl
集成的代理服务器
可以通过 web 浏览器监视服务器的状态,
可以自定义日志
支持服务器端包含命令(ssi)
支持安全 socket 层(ssl)
具有用户会话过程的跟踪能力
支持 fastcgi
支持 Java

Nginx

Nginx 是俄罗斯人编写的十分轻量级的 HTTP 服务器,Nginx,它的发音为“engine X”,
是一个高性能的 HTTP 和反向代理服务器,同时也是一个 IMAP/POP3/SMTP 代理服务器.Nginx 是由俄罗斯人 Igor
Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发.

Nginx 以事件驱动的方式编写,所以有非常好的性能,同时也是一个非常高效的反向代理、负载平衡。其拥有匹配
Lighttpd 的性能,同时还没有 Lighttpd 的内存泄漏问题,而且 Lighttpd 的 mod_proxy 也有一些问题并且很久没有更新。但是 Nginx 并不支持 cgi 方式运行,原因是可以减少因此带来的一些程序上的漏洞。所以必须使用 FastCGI 方式来执行 PHP 程序。

nginx 做为 HTTP 服务器,有以下几项基本特性:

处理静态文件,索引文件以及自动索引;打开文件描述符缓冲 无缓存的反向代理加速,简单的负载均衡和容错 FastCGI,简单的负载均衡和容错
模块化的结构。包括 gzipping, byte ranges, chunked responses,以及
SSI-filter 等 filter。如果由 FastCGI 或其它代理服务器处理单页中存在的多个 SSI,则这项处理可以并行运行,而不需要相互等待。
Nginx 专为性能优化而开发,性能是其最重要的考量,实现上非常注重效率。它支持内核 Poll 模型,能经受高负载的考验,有报告表明能支持高达
50,000 个并发连接数。

Nginx 具有很高的稳定性。其它 HTTP 服务器,当遇到访问的峰值,或者有人恶意发起慢速连接时,也很可能会导致服务器物理内存耗尽频繁交换,失去响应,只能重启服务器。例如当前 apache 一旦上到 200 个以上进程,web 响应速度就明显非常缓慢了。而 Nginx 采取了分阶段资源分配技术,使得它的 CPU 与内存占用率非常低。nginx 官方表示保持 10,000 个没有活动的连接,它只占 2.5M 内存,所以类似 DOS 这样的攻击对 nginx 来说基本上是毫无用处的。就稳定性而言,nginx 比 lighthttpd 更胜一筹。

Nginx 支持热部署。它的启动特别容易,
并且几乎可以做到 7X24 不间断运行,即使运行数个月也不需要重新启动。你还能够在不间断服务的情况下,对软件版本进行进行升级。

三种服务器比较

Nginx 安装

Mac Nginx 安装(Brew)

Homebrew

1
$ man brew

安装 Homebrew

1
$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

卸载

1
$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/uninstall)"

其他常用命令:

1
2
3
localhost:~ wany$ brew --version  (查看当前电脑所安装的brew版本)

localhost:~ wany$ brew update (更新电脑中的brew版本)

通过 brew 安装 Nginx

1
$ sudo /usr/local/sbin/nginx

注意事项:
安装 nignx, brew 所安装的软件都保存在 :/usr/local/Cellar/
nginx 配置文件保存到了:/usr/local/etc/nginx/nginx.conf

建立软连接

1
$ ln -s /usr/local/bin/nginx  /usr/local/bin/nginx

启动

1
$ sudo nginx

重启

1
$ sudo nginx -s reload

Nginx 反向代理

用 nginx 的反向代理机制解决前端跨域问题

什么是跨域以及产生的原因

跨域是指 a 页面想获取 b 页面资源,如果 a、b 页面的协议、域名、端口、子域名不同,或是 a 页面为 ip 地址,b 页面为域名地址,所进行的访问行动都是跨域的,而浏览器为了安全问题一般都限制了跨域访问,也就是不允许跨域请求资源。

跨域情况如下:

跨域常见的解决方法

目前来讲没有不依靠服务器端来跨域请求资源的技术

  • 1.jsonp 需要目标服务器配合一个 callback 函数。

  • 2.window.name+iframe 需要目标服务器响应 window.name。

  • 3.window.location.hash+iframe 同样需要目标服务器作处理。

  • 4.html5 的 postMessage+ifrme 这个也是需要目标服务器或者说是目标页面写一个 postMessage,主要侧重于前端通讯。

  • 5.CORS 需要服务器设置 header :Access-Control-Allow-Origin。

  • 6.nginx 反向代理 这个方法一般很少有人提及,但是他可以不用目标服务器配合,不过需要你搭建一个中转 nginx 服务器,用于转发请求。

Nginx 反向代理解决跨域

修改配置文件:

路径

1
2
luoyecs-iMac:nginx luoyec$ pwd
/usr/local/etc/nginx

修改 nginx.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
listen       9000;		#监听9000端口号,
server_name localhost; #当前服务器域名,一般是开发者本地电脑

#charset koi8-r;

#access_log logs/host.access.log main;

location / {
# root html; # 根路径
# index index.html index.htm; #根路径下的入口文件
proxy_pass http://localhost:3000;
}

location /mobile/ { # 注意这里可以写正则表达式,(匹配规则,用于拦截请求,匹配任何以 /proxy/html/开头的地址,匹配符合以后,停止往下搜索正则)
rewrite ^/mobild/(.*)$ /$1 break; #代表重写拦截进来的请求,并且只能对域名后边的除去传递的参数外的字符串起作用,例如www.c.com/proxy/html/api/msg?method=1&para=2重写。只对/proxy/html/api/msg重写。
proxy_pass http://www.daolimen.com; # 既是把请求代理到其他主机
}

重启 nginx

1
$ sudo nginx -s reload

在浏览器中访问:
http://localhost:9000/

配置说明

首先找到 nginx.conf 或者 nginx.conf.default 或者是 default 里面的这部份

其中 server 代表启动的一个服务,location 是一个定位规则。

1
2
3
4
5
location /{   #所有以/开头的地址,实际上是所有请求

root html #去请求../html文件夹里的文件,其中..的路径在nginx里面有定义,安装的时候会有默认路

index index.html index.htm #首页响应地址

从上面可以看出 location 是 nginx 用来路由的入口,所以我们接下来要在 location 里面完成我们的反向代理。

假如我们我们是 www.a.com/html/msg.html 想请求 www.b.com/api/?method=1&para=2;

我们的 ajax:

1
2
3
4
5
6
7
var url = 'http://www.b.com/api/msg?method=1&para=2'
<br>$.ajax({
type: "GET",
url:url,
success: function(res){..},
....
})

上面的请求必然会遇到跨域问题,这时我们需要修改一下我们的请求 url,让请求发在 nginx 的一个 url 下。

1
2
3
4
5
6
7
8
9
var url = 'http://www.b.com/api/msg?method=1&para=2';
var proxyurl = 'msg?method=1&para=2';
//假如实际地址是 www.c.com/proxy/html/api/msg?method=1&para=2; www.c.com是nginx主机地址
$.ajax({
type: "GET",
url:proxyurl,
success: function(res){..},
....
})

再在刚才的路径中匹配到这个请求,我们在 location 下面再添加一个 location。

1
2
3
4
location ^~/proxy/html/{
rewrite ^/proxy/html/(.*)$ /$1 break;
proxy_pass http://www.b.com/;
}

以下做一个解释:

  • '^~ /proxy/html/ '

就像上面说的一样是一个匹配规则,用于拦截请求,匹配任何以 /proxy/html/开头的地址,匹配符合以后,停止往下搜索正则。

  • rewrite ^/proxy/html/(.*)$ /$1 break;

代表重写拦截进来的请求,并且只能对域名后边的除去传递的参数外的字符串起作用,例如 www.c.com/proxy/html/api/msg?method=1&para=2 重写。只对/proxy/html/api/msg 重写。

rewrite 后面的参数是一个简单的正则 ^/proxy/html/(.*)$ ,$1 代表正则中的第一个(),$2 代表第二个()的值,以此类推。

break 代表匹配一个之后停止匹配。

  • proxy_pass
既是把请求代理到其他主机,其中 http://www.b.com/ 写法和 http://www.b.com写法的区别如下:

不带/

1
2
3
4
location /html/
{
  proxy_pass http://b.com:8300;
}

带/

1
2
3
4
location /html/
{
proxy_pass http://b.com:8300/;
}

上面两种配置,区别只在于 proxy_pass 转发的路径后是否带 “/”。

针对情况 1,如果访问 url = http://server/html/test.jsp,则被nginx代理后,请求路径会便问http://proxy_pass/html/test.jsp,将test/ 作为根路径,请求 test/路径下的资源。

针对情况 2,如果访问 url = http://server/html/test.jsp,则被nginx代理后,请求路径会变为 http://proxy_pass/test.jsp,直接访问server的根资源。