推荐 | 如何用Nginx来助力前端开发

5,829 阅读8分钟

“谁说前端需要懂Nginx了?”

“前端凭什么要学习Nginx?”

“不用Nginx,我们前端的日子不也是照过吗?”

在找 nginx 文章的时候,经常看到类似的标题......我只想说一句——

很多前端开发者一直对 Nginx 有误会,认为 Nginx 是偏后端的知识,我们前端不需要懂,更没必要去使用它。

但是等笔者熟悉了 Nginx 之后,发现其实用好 Nginx 可以解放我们的前端生产力,用来助力我们的前端开发。(对 Nginx 不熟的点这里

1. 快速部署静态应用

这个场景自不必说,Nginx 本身就是一个 web 服务器。

Nginx 部署静态应用只需要改一行配置,而我们前端号称“终将统一宇宙”的 Node.js 至少也需要6行代码。

这里当然不是在比较孰优孰劣的问题,只是在静态应用部署这块,Nginx 使起来确实要更快速、方便。

参考代码:

# 首尾配置暂时忽略
server {  
        listen       8080;        
        server_name  localhost;

        location / {
            # root   html; # Nginx默认路径
            root /usr/local/var/www/my-project; # 设置为个人项目的根目录路径
            index  index.html index.htm;
        }
}
# 首尾配置暂时忽略

只需要将 root 属性值改为你要部署的绝对路劲(我的是/usr/local/var/www/my-project)即可。

2. 请求过滤

设置访问白名单

当你的项目没有灰度环境,又想在功能上线后先让测试同事试用一下的时候,就需要设置访问的白名单了。

如果你的项目用上了 nginx 做代理,你就会发现这就是小菜一碟。

参考代码:

# 首尾配置暂时忽略
server {
        listen       8080;        
        server_name  localhost;

        location / {
            # IP访问限制(只允许IP是 10.81.1.11 的机器才能访问)
            allow 10.81.1.11;
            deny all;
            
            root   html;
            index  index.html index.htm;
        }
}
# 首尾配置暂时忽略

上面代码块中的IP改成你们测试同事机器的IP即可。Nginx 这种顾名思义、一目了然的配置连讲解都显得很多余。

讲到这,我脑子里突然闪过《舌尖上的中国》中的一句话:

高端的食材,往往只需要采用最简单的烹饪方式。

配置图片防盗链

笔者刚参加工作之初遇到过这个问题:

为了不等设计师出图,便想先开发完功能再替换图片。这时候我将从百度找到尺寸差不多的图片引入项目中,竟然发现图片不能正常显示,提示“该图片仅限百度内部用户交流使用”。最后不得不下载这张图片,放入项目中使用。

后来经验渐长,我明白了这是因为百度将图片做了防盗链处理,不允许别的网站以外链的方式进行引用。

那么当我们的项目也想保护自己的图片权益,设置图片防盗链的时候我们怎么实现呢?

# 首尾配置暂时忽略
server {
        listen       8080;        
        server_name  localhost;

        location / {
            root   /usr/local/var/www/my-project; # 设置为个人项目的根目录路径
            index  index.html index.htm;
        }
        
        # 图片防盗链
        location ~* \.(gif|jpg|jpeg|png|bmp|swf)$ {
            valid_referers none blocked 192.168.0.103; # 只允许本机IP外链引用
            if ($invalid_referer){
                return 403;
            }
        }
}
# 首尾配置暂时忽略

上面代码块设置了只允许本机IP外链引用图片资源,其他域名下的请求都会被403禁止访问。

3. 解决跨域

跨域是前端经常会遇到的问题,解决的方式有很多,例如:jsonp、node.js中转、CORS等。

但是使用 Nginx 来跨域简单明了,主要用到的是 Nginx 的反向代理原理。

参考代码:

# 首尾配置暂时忽略
server {
        listen       8080;        
        server_name  localhost;

        location / {
            # 跨域代理设置
            proxy_pass http://www.proxy.com; # 要实现跨域的域名
            add_header Access-Control-Allow-Origin *;
            add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
            add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
        }
}
# 首尾配置暂时忽略

思路就是在反向代理请求过程中,增加可以跨域访问的请求头。不得不说这个方式真香,似乎帮我们前端打开了通往跨域的新大门~

4. 适配PC和移动端

我们在开发一些门户或者对外网站的时候,经常要考虑使用移动端和PC端两套页面。因为单纯使用一个页面来做自适应,有时候总是会有些捉襟见肘。

之前我们使用的方案多数是整两个 domain,一个叫xxx.com,另一个叫m.xxx.com。亦或是搞两套路由来进行区分,移动端所有路由前面都增加一个 path,如xxx.com/login,则对用移动端的路由就设成xxx.com/m/login

这两种方式其实都存在一个问题—— PC 和移动端所有的 url 都不一样,给用户的体验并不是太好。

最关键的是还需要处理一个逻辑,无论是每个移动端页面,还是PC端页面,在页面开始渲染的时候都要再根据 navigator.userAgent,进行一次重定向。因为要保证PC端和移动端的路由要能根据设备,互相进行跳转。每个页面都要处理这个,这显得非常的多余。

如果使用 Nginx 处理这个,就显得再适合不过了。

参考代码:

# 首尾配置暂时忽略
server {
        listen       8080;        
        server_name  localhost;

        location / {
            # 适配移动端/PC端配置
            set $type "pc";
            if ($http_user_agent ~* (mobile|nokia|iphone|ipad|android|samsung|htc|blackberry)) {
                set $type "mobile";
            }
            root /usr/local/var/www/my-project/$type; # 根据设备类型选择设定根目录文件夹名(pc/mobile)
            index  index.html index.htm;
        }
}
# 首尾配置暂时忽略

这个配置稍微多一点,主要思路也是通过判断浏览器的 useragent 来取对应的静态页面资源。

如果我们的前端应用部署后是有服务的怎么办呢?那就不取对应的静态页面,而是 proxy_pass 代理到对应的页面路由上即可。

5. Gzip 压缩

这个功能基于 ngx_http_gzip_module 模块,该模板是nginx内置的

日常开发中,我们经常遇到前端静态资源比较大导致页面响应变慢的问题。通常我们的做法是将静态资源放入CDN服务中。

但是对于有些不适合接或者来不及接CDN的,我们就可以开启 Nginx 的gzip功能,快速完成队 html、css、js 等静态资源的压缩。要注意的是,图片资源压缩前后区别不大,gzip压缩图片还会白白消耗服务器资源,得不偿失。

开启 Nginx 的gzip功能,参考配置如下:

http {
    # 配置gzip压缩
    gzip  on;
    gzip_min_length 1000; # 设定压缩的临界点
    gzip_comp_level 3; # 压缩级别
    gzip_types      text/plain application/xml; # 要压缩的文件类别
}

没开启 gzip 压缩之前(该html是598kb):

开启 gzip 压缩后(该html是517kb):

如图二中的红框标识,能看到响应头带上了Content-Encoding: gzip 标识,就说明你配置的gzip压缩功能起效果了。

6. 合并请求

从这个部分开始,需要使用 Nginx 第三方扩展模块了,故需要使用编译版的 Nginx(传送门 Mac OS下安装及配置nginx)。

web前端性能优化中很重要的一条就是减少 http 请求数。而通过淘宝开发的 nginx-http-concat 第三方模块,我们可以实现多请求的合并。

配置好 Nginx 的合并请求功能后,前端就可以用一种特殊的 url 请求规则(例如example.com/??1.js,2.js,3.js )向 Nginx 发起请求。

此时,Nginx 会将前端想要的多个资源请求合并成一个请求返回给前端,极大的减少了网络请求时间的开销。

参考配置如下:

server {
    ......
    # 新增一个 location,static 为静态资源目录
    location /static/ {
        concat on; # 是否打开资源合并开关
        concat_types application/javascript; # 允许合并的资源类型
        concat_unique off; # 是否允许合并不同类型的资源
        concat_max_files 20; # 允许合并的最大资源数目
    }
}

7. 图片处理

需要第三方模块 ngx_http_image_filter_module 支持

主要是可以帮助前端完成一些对图片裁剪/缩放/旋转/图片品质等参数的调整。

参考配置如下:

Nginx 配置好这个模块之后,你只需要访问类似 http://127.0.0.1:8080/img/weiciyun.jpeg?w=100&h=100 这种url,就可以拿到你想要的图片资源。针对是极大的丰富了我们的前端生产力。

8. 修改网页内容

Nginx 内置了但是没有默认启用的 Module ngx_http_sub_module 模块,能让 Nginx 具备替换页面代码块的能力。

参考配置如下:

location / {
    ......
    # 在 <body> 中插入一段 html 片段
    sub_filter '</body>' '<p>好嗨哟~我是插入的html片段</p></body>'
}

引入第三方模块 nginx-http-footer-filter 后,可以实现直接向页面底部插入代码块的能力。

Nginx 引入了这两个模块后直接给前端赋能,这给我们前端提供了无限的可能。比如:

  • 快速切换开发环境(将域名访问替换掉ip访问,实现不同环境的切换)
  • 移动页面增加二维码方便扫描访问(增加页面网址生成二维码的js,手机扫一扫就能进入你的移动页面)
  • js文件底部插入sourceMappingURL方便debug线上问题
  • ......

这个应用场景看起来应该是是最贴近前端开发,直接跟我们最熟悉的 html/js/css 打交道,这对我们前端来说有一种久违的熟悉感。非常推荐大家去试一试。

总结

Nginx 助力前端开发的场景应该远远不止本文中的8个,笔者这里权当抛砖引玉,更多、更好的用法还在等着大家去探索和发现。

最后,有两句话想送给大家——

在技术上不要自我局限,我们首先是工程师,其次才是前端工程师。

前端只是你的一个发力点,而不要让前端成为你的边界。