从前端角度了解nginx
21 October 2018

以前的我只是写写前端,貌似不了解nginx也没什么关系,但是写node服务端后,开始发现不了解这个玩意,很多东西不知道怎么实现的,了解了一些之后,会发现,原来这么多神奇的事都是nginx提供的能力达成的,倒是解释了不少以前遇到的不能理解的现象~总之,虽然是个前端,多了解一点nginx绝对没有坏处。

用node写一个服务后,虽然没有nginx也能跑起来,但是有没有想过,最基础的一个场景,一台机器上要跑不同端口的多个服务,怎么做到对外透出?毕竟外部过来的域名访问解析后都是去访问80端口了。还有static、proxy的服务其实用nginx做起来更方便彻底,性能还好。

入门

万事开头难,学东西最靠谱的看官方文档。不过可能去nginx官网翻了半天都是产品介绍。。。所以贴心的送上下官方文档链接:

有哪些模块我也就不重复写了,反正官网都能了解到,而且说得更权威。

简介版还可以看看这篇文章:https://www.jianshu.com/p/bed000e1830b

cd /usr/local/etc/nginx && sudo nginx #去对应目录启动
nginx -s reload #重启
nginx -s quit #安全退出
nginx -s stop #快速退出

什么安装启动就不多说了,看官网

功能

说说我认知到的nginx和大前端领域的结合点

静态服务器

可以起个静态服务器,访问静态资源。这是nginx的基本能力,利用server模块简单配配就能做到。

server {
    listen 80;
    server_name site.nginx.com;
    index static/index.html;
    location / {
        root /Users/echizen/demo/nginx-learn/site1;
    }
}

本地绑上host127.0.0.1 site.nginx.com,访问http://site.nginx.com就能看到/Users/echizen/demo/nginx-learn/site1/static/index.html下的文件内容了。

注意:如果没有配置index 会默认找root下的index.html文件,找不到会报403,这个403有点迷惑性

这个功能不算是nginx必须存在的一个功能,毕竟能做到的方式太多:

  • 线上用的话,node里有很多处理静态文件的库,譬如koa-static
  • 如果是本地测试目的,要起个静态服务器,配置nginx显得过于麻烦,不如去项目目录下, 用python起一下 python -m SimpleHTTPServer <port>

但是nginx层能做的是动静态内容分离,并且进行一些缓存优化措施。if-modify-since, Cache-Control, Expires这些缓存相关的配置都可以通过nginx。

反向代理

这个功能是nginx的一个亮点。

反向代理是什么呢?

反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。

举个例子,比如我想访问 http://www.test.com/readme ,但www.test.com上并不存在readme页面,于是他是偷偷从另外一台服务器上取回来,然后作为自己的内容返回用户,但用户并不知情。这里所提到的 www.test.com 这个域名对应的服务器就设置了反向代理功能。

正向代理(Forward Proxy)通常都被简称为代理,就是在用户无法正常访问外部资源,比方说受到GFW的影响无法访问twitter的时候,我们可以通过代理的方式,让用户绕过防火墙,从而连接到目标网络或者服务。

正向代理的工作原理就像一个跳板,比如:我访问不了google.com,但是我能访问一个代理服务器A,A能访问google.com,于是我先连上代理服务器A,告诉他我需要google.com的内容,A就去取回来,然后返回给我。从网站的角度,只在代理服务器来取内容的时候有一次记录,有时候并不知道是用户的请求,也隐藏了用户的资料,这取决于代理告不告诉网站。 作者:猿码道: 链接:https://www.jianshu.com/p/bed000e1830b

通过反向代理,可以实现:

  • 一台机器充分利用多个域名
  • 本地通过80端口代理到实际服务的端口,解决调试时端口带来的跨域问题。(不过更也可以用charles设定   通过node proxy工具如:node-http-proxy, koa-proxy)

for example:

server {
    listen 80;
    server_name site1.nginx.com;
    index static/index.html;
    location / {
        root /Users/echizen/demo/nginx-learn/site1;
    }

    location /api {
        proxy_pass http://127.0.0.1:8020;
    }
}

server {
    listen 80;
    server_name site2.nginx.com;
    index static/index.html;
    location / {
        root /Users/echizen/demo/nginx-learn/site2;
    }

    location /api {
        proxy_pass http://127.0.0.1:8021;
    }
}

这样访问http://site1.nginx.com就能看到site1的内容,http://site1.nginx.com/api/*可以看到site1下的接口服务,http://site2.nginx.com能看到site2的内容,http://site2.nginx.com/api/*可以看到site2的接口服务。实现了一台机器上提供多个独立的服务

重定向到对应的pc、h5站点

很多网站pc和h5站点的域名是区分的,譬如蘑菇街pc是https://www.mogujie.com, h5是https://m.mogujie.com,会做到用户通过pc的机器打开https://m.mogujie.com链接自动跳转到pc的https://www.mogujie.com。

这个功能通过nginx来判断$http_user_agent, 然后rewrite就能实现。

合并请求

网站性能优化,为了减少请求数,常将一定量的请求合并。

image

通过nginx-http-concat模块(前端可以将多个资源的请求合并成一个请求,后台Nginx会获取各个资源并拼接成一个结果进行返回。

Nginx配置, for example:

location /__/mfp/ {
    concat on; # 是否打开资源合并开关
    concat_types application/javascript; # 允许合并的资源类型
    concat_unique off; # 是否允许合并不同类型的资源
    concat_max_files 20; # 允许合并的最大资源数目
}

权限控制

某些站点需要进行权限控制,譬如公司内网只允许在公司的内部网络里访问。用ngx_http_access_module模块的denyallow就能做到

eg:

location / {
    deny  192.168.1.100;
    allow 192.168.1.10/200;
    allow 10.110.50.16;
    deny  all;
}

负载均衡

这个前端可能没有感知,但是也是nginx的一大核心功能。当一个服务部署在多台机器上构成集群时,为了避免流量不均衡导致部分机器压力过大部分机器限制,都是要设置负载均衡方案的。upstream 模块负责负载均衡模块,通过一个简单的调度算法来实现客户端IP到后端服务器的负载均衡。

eg:

upstream site.nginx.com{
    ip_hash; # 调度算法
    server 192.168.1.101:80;
    server 192.168.1.102:80 down;
    server 192.168.1.103:8080  max_fails=3  fail_timeout=20s;
    server 192.168.1.104:8080;
}

第一行是调度算法,也就是流量分配策略,后面的server是构成集群的机器。

有4种基础的调度算法:

  • weight 轮询(默认)。每个请求按时间顺序逐一分配到不同的后端服务器,如果后端某台服务器宕机,故障系统被自动剔除,使用户访问不受影响。weight。指定轮询权值,weight值越大,分配到的访问机率越高,主要用于后端每个服务器性能不均的情况下。

  • ip_hash。每个请求按访问IP的hash结果分配,这样来自同一个IP的访客固定访问一个后端服务器,有效解决了动态网页存在的session共享问题。

  • fair(第三方)。比上面两个更加智能的负载均衡算法。此种算法可以依据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间来分配请求,响应时间短的优先分配。upstream_fair模块提供。

  • url_hash(第三方)。按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,可以进一步提高后端缓存服务器的效率,也降低了session等需要共享信息的复杂度。使用要安装hash软件包。

server 指定服务器ip和端口,以及在负载均衡调度中的状态。常用的状态有:

  • down,表示当前的server暂时不参与负载均衡。
  • backup,预留的备份机器。当其他所有的非backup机器出现故障或者忙的时候,才会请求backup机器,因此这台机器的压力最轻。
  • max_fails,允许请求失败的次数,默认为1。当超过最大次数时,返回proxy_next_upstream 模块定义的错误。
  • fail_timeout,在经历了max_fails次失败后,暂停服务的时间。max_fails可以和fail_timeout一起使用。

参考文献