谁说前端不需要知道Nginx

lxf2023-12-16 12:00:02

简介

随着前端变革,Nginx也成为了前端开发工程师必不可少应该具备的一项技能了,学习Nginx可以让我们更加了解前端项目上线部署的整个流程,可以让我们碰到一些服务问题能快速定位并解决。

好啦,话不多说直接上干货。

Nginx是什么

Nginx是一款轻量级的HTTP服务器,采用事件驱动的异步非阻塞处理方式框架,这让其具有极好的IO性能,时常用于服务端的反向代理和负载均衡。

Nginx常用命令

nginx -v # 查看nginx版本
nginx -s reload  # 向主进程发送信号,重新加载配置文件,热重启
nginx -s reopen	 # 重启 Nginx
nginx -s stop    # 快速关闭
nginx -s quit    # 等待工作进程处理完成后关闭
nginx -T         # 查看当前 Nginx 最终的配置
nginx -t -c <配置路径>    # 检查配置是否有问题,如果已经在配置目录,则不需要-c

ps -ef | grep nginx # 全格式显示所有 nginx 运行进程
kill -9 PID(进程ID)# 杀死单个进程,可以利用这个命令杀死Nginx进程

systemctlLinux 系统应用管理工具 systemd 的主命令,用于管理系统,我们也可以用它来对 Nginx 进行管理,相关命令如下:

systemctl start nginx    # 启动 Nginx
systemctl stop nginx     # 停止 Nginx
systemctl restart nginx  # 重启 Nginx
systemctl reload nginx   # 重新加载 Nginx,用于修改配置后
systemctl enable nginx   # 设置开机启动 Nginx
systemctl disable nginx  # 关闭开机启动 Nginx
systemctl status nginx   # 查看 Nginx 运行状态

配置文件分析

nginx.conf 结构大概如下:

main        # 全局配置,对全局生效
├── events  # 配置影响 Nginx 服务器或与用户的网络连接
├── http    # 配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置
│   ├── upstream # 配置后端服务器具体地址,负载均衡配置不可或缺的部分
│   ├── server   # 配置虚拟主机的相关参数,一个 http 块中可以有多个 server 块
│   ├── server
│   │   ├── location  # server 块可以包含多个 location 块,location 指令用于匹配 uri
│   │   ├── location
│   │   └── ...
│   └── ...
└── ...

代理

代理有正向代理和反向代理之分。

谁说前端不需要知道Nginx

简单总结就是正向代理知道真实的服务器。反向代理是不知道真实服务器,把代理服务器当做真实服务器。

Nginx就是一个典型的反向代理服务器。

正向代理

正向代理: 一般的访问流程是客户端直接向目标服务器发送请求并获取内容,使用正向代理后,客户端改为向代理服务器发送请求,并指定目标服务器(原始服务器),然后由代理服务器和原始服务器通信,转交请求并获得的内容,再返回给客户端。

正向代理隐藏了真实的客户端,为客户端收发请求,使真实客户端对服务器不可见;

反向代理

反向代理: 与一般访问流程相比,使用反向代理后,直接收到请求的服务器是代理服务器,然后将请求转发给内部网络上真正进行处理的服务器,得到的结果返回给客户端。

反向代理隐藏了真实的服务器,为服务器收发请求,使真实服务器对客户端不可见。一般在处理跨域请求的时候比较常用。现在基本上所有的大型网站都设置了反向代理。

反向代理在Nginx里面主要有两个作用,第一就是实现负载均衡、第二个就是我们非常熟悉的解决跨域。

反向代理配置

下面我们以vue项目部署为例,来说说Nginx的反向代理配置。

server {
  listen       80;
  server_name  localhost;
  location / {
    root html/dist; # 指向vue目录 
    index index.html index.htm; # index指向 html/dist/index文件
    try_files $uri $uri/ /index.html; # history模式 404问题
  }
  
  location /api/ {
    proxy_pass http://127.0.0.1:5000/;
  }
}

上面的例子

当我们访问 localhost -> 就会定位到html/dist/index.html文件

当我们访问 localhost/api/upload -> 就会去访问http://127.0.0.1:5000/upload

在反向代理配置过程中,对于location后的url的配置还有很多细节。它支持四个不同的前缀=、~、~*、^~

location[ = | ~ | ~* | ^~ ] url{}

location 前缀 =、~、~*、^~

=

= 用于不含正则表达式的 url 前,要求字符串与 url 严格匹配,匹配成功就停止向下搜索并处理请求。

~

~ 用于表示 url 包含正则表达式,并且区分大小写。

~*

~* 用于表示 url 包含正则表达式,并且不区分大小写。

^~

^~ 用于不含正则表达式的 url 前,要求 Nginx 服务器找到表示 url 和字符串匹配度最高的 location 后,立即使用此 location 处理请求,而不再匹配。

location和proxy_pass

对于locationproxy_pass后面的/还是有几个点需要注意,我们这里再说明一下。可能会有小伙伴或经常被这个问题所困惑。

location和proxy_pass都带/

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

则真实地址不带/

当我们访问 localhost/api/upload -> 就会去访问http://127.0.0.1:5000/upload

location不带/,proxy_pass带/

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

则真实地址会带/

当我们访问 localhost/api/upload -> 就会去访问http://127.0.0.1:5000//upload

location带/,proxy_pass不带/

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

则真实地址会带location匹配目录

当我们访问 localhost/api/upload -> 就会去访问http://127.0.0.1:5000/api/upload

location和proxy_pass都不带/

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

则真实地址会带location匹配目录

当我们访问 localhost/api/upload -> 就会去访问http://127.0.0.1:5000/api/upload

跨域

跨域笔者在浏览器架构、渲染流程、调试、重绘回流、跨域知识梳理里面有详细讲解,这里就不再细说了。这里我们只说说怎么用Nginx来解决跨域。

Nginx解决跨域有两种方式,第一种就是使用上面我们说的反向代理。第二种就是配置cors 跨域资源共享

配置反向代理

server{ 
  listen 8888; 
  server_name 127.0.0.1;

  location / {
    proxy_pass 127.0.0.1:8000; 
  } 
}

它的原理就是利用服务器之间不存在跨域的特性,Nginx充当中间商,转发请求和转发响应。这里的代理服务器就是Nginx

谁说前端不需要知道Nginx

配置cors

Nginx还可以给我们的响应添加响应头,所以利用这个特性,我们还可以利用Nginx配置cors

location / {
    # 允许跨域的请求,可以自定义变量$http_origin,*表示所有
    add_header 'Access-Control-Allow-Origin' *;
    # 允许携带cookie请求
    add_header 'Access-Control-Allow-Credentials' 'true';
    # 允许跨域请求的方法:GET,POST,OPTIONS,PUT
    add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT';
    # 允许请求时携带的头部信息,*表示所有
    add_header 'Access-Control-Allow-Headers' *;
    # 允许发送按段获取资源的请求
    add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
    # 一定要有!!!否则非简单请求无法进行跨域!
    # 在发送非简单请求前,会以Options方式发送预检请求,服务器接受时才会正式请求
    if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain; charset=utf-8';
        add_header 'Content-Length' 0;
        # 对于Options方式的请求返回204,表示接受跨域请求
        return 204;
    }
}

负载均衡

在请求爆发式增长的情况下,单个机器性能再强劲也无法满足要求了,这个时候集群的概念产生了,单个服务器解决不了的问题,可以使用多个服务器,然后将请求分发到各个服务器上,将负载分发到不同的服务器,这就是负载均衡,核心是「分摊压力」。

负载均衡主要思想就是把负载均匀合理地分发到多个服务器上,实现压力分流的目的。

先来看看Nginx引入前后,客户端请求处理流程的对比:

谁说前端不需要知道Nginx

原本客户端是直接请求目标服务器,由目标服务器直接完成请求处理工作,但加入Nginx后,所有的请求会先经过Nginx,再由其进行分发到具体的服务器(一个或多个)处理,处理完成后再返回Nginx,最后由Nginx将最终的响应结果返回给客户端。Nginx根据一定的规则,将请求分发到不同的服务器,这个过程就是负载均衡。

负载均衡种类

Nginx 提供了好几种分配方式,默认为轮询,就是轮流来。有以下几种分配方式:

  1. 轮询,默认方式,每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务挂了,能自动剔除;
  2. weight,权重分配,指定轮询几率,权重越高,在被访问的概率越大,用于后端服务器性能不均的情况;
  3. ip_hash,每个请求按访问 IP 的 hash 结果分配,这样每个访客固定访问一个后端服务器,可以解决动态网页 session 共享问题。负载均衡每次请求都会重新定位到服务器集群中的某一个,那么已经登录某一个服务器的用户再重新定位到另一个服务器,其登录信息将会丢失,这样显然是不妥的;
  4. fair(第三方),按后端服务器的响应时间分配,响应时间短的优先分配,依赖第三方插件 nginx-upstream-fair,需要先安装;

负载均衡配置

http {
  upstream myserver {
    # ip_hash;  # ip_hash 方式
    # fair;   # fair 方式
    server 127.0.0.1:8081;  # 负载均衡目的服务地址
    server 127.0.0.1:8080;
    server 127.0.0.1:8082 weight=10;  # weight 方式,不写默认为 1
    server 127.0.0.1:8083 down; # 该 server 不参与负载均衡
  }
 
  server {
    location / {
      proxy_pass http://myserver; # 使用负载均衡
    }
  }
}

动静分离

动静分离简单理解就是将动态资源和静态资源通过 Nginx 分开配置,加快解析速度。其次静态资源可以单独配置缓存。

动静分离配置

server {
  # 动态资源
  location /www/ {
    root /data/;
    index index.html index.htm;
  }
  
  # 静态资源
  location /image/ {
    root /data/;
    autoindex on; # 开启静态资源目录
    expires 10d; # 缓存时间为10天
    # expires -1; # 如果不希望缓存 
  }
}

常用技巧

图片防盗链

valid_referers:设置可访问资源的规则,若不允许匹配上则 $invalid_referer 值为1,对不允许的规则我们可以返回403。

valid_referers常用配置如下:

字段含义
none允许没有 referer 字段的请求访问资源
blocked允许非 HTTP(S) 开头的请求访问资源
server_names允许指定域名 / IP 访问资源
[string]正则匹配定义可访问资源的网址

这里我们配置了none blocked*.randy.com

location ~/static/.*.(jpg|jpeg|png|gif|webp)$ {
  root /home;
  valid_referers none blocked server_names *.randy.com;
  if ($invalid_referer) {
    return 403;
  }
}

IP白名单、黑名单

location / {
  allow 192.168.10.2; # 只允许IP是 192.168.0.2 机器访问
  deny all; # 禁止所有IP
  
  root   html;
  index  index.html index.htm;
}

请求方法限制

非指定请求全返回 403。

if ($request_method !~ ^(GET|POST|HEAD)$) {
  return 403;
}

PC端和移动端使用不同项目

location / {
  root /home/static/pc;
  if ($http_user_agent ~* '(mobile|android|iphone|ipod|phone)') {
    root /home/static/mobile;
  }
  index index.html;
}

HTTP 自动跳转至 HTTPS

server {
  listen       80;
  server_name  www.randy.vip;
  rewrite ^(.*) https://$server_name$1 permanent;
}

后记

感谢小伙伴们的耐心观看,本文为笔者个人学习笔记,如有谬误,还请告知,万分感谢!如果本文对你有所帮助,还请点个关注点个赞~,您的支持是笔者不断更新的动力!

本网站是一个以CSS、JavaScript、Vue、HTML为核心的前端开发技术网站。我们致力于为广大前端开发者提供专业、全面、实用的前端开发知识和技术支持。 在本网站中,您可以学习到最新的前端开发技术,了解前端开发的最新趋势和最佳实践。我们提供丰富的教程和案例,让您可以快速掌握前端开发的核心技术和流程。 本网站还提供一系列实用的工具和插件,帮助您更加高效地进行前端开发工作。我们提供的工具和插件都经过精心设计和优化,可以帮助您节省时间和精力,提升开发效率。 除此之外,本网站还拥有一个活跃的社区,您可以在社区中与其他前端开发者交流技术、分享经验、解决问题。我们相信,社区的力量可以帮助您更好地成长和进步。 在本网站中,您可以找到您需要的一切前端开发资源,让您成为一名更加优秀的前端开发者。欢迎您加入我们的大家庭,一起探索前端开发的无限可能!