range

If there were you, the world would be just right

0. 主要内容

  1. nginx结合Apache实现动静分离
  2. nginx跨域
  3. nginx缓存

1. nginx结合Apache实现动静分离

动静分离的优势

api接口服务化:动静分离之后,后端应用更为服务化,只需要通过提供api接口即可,可以为多个功能模块甚至是多个平台的功能使用,可以有效的节省后端人力,更便于功能维护。

前后端开发并行:前后端只需要关心接口协议即可,各自的开发相互不干扰,并行开发,并行自测,可以有效的提高开发时间,也可以有些的减少联调时间

减轻后端服务器压力,提高静态资源访问速度:后端不用再将模板渲染为html返回给用户端,且静态服务器可以采用更为专业的技术提高静态资源的访问速度。

2. nginx跨域

跨源资源共享(CORS)是一种机制,它使用额外的HTTP标头让用户代理获得访问来自不同来域的服务器上选定资源的权限,而不是使用当前正在使用的站点。用户代理在请求来自与当前文档不同的域,协议或端口的资源时,会发出跨源HTTP请求。

产生跨域的原因?

  • 出于安全原因,浏览器限制从脚本内发起的跨域HTTP请求。例如,XMLHttpRequest与提取API遵循同域策略。这意味着使用这些API的Web应用程序只能从加载应用程序的同一个域请求HTTP资源,除非使用CORS头文件。
  • 浏览器为了安全问题一般都限制了跨域访问,也就是不允许跨域请求资源
  • 同ip (或domain),同端口,同协议视为同一个域,一个域内的脚本仅仅具有本域内的权限,可以理解为本域脚本只能读写本域内的资源,而无法访问其它域的资源。这种安全限制称为同源策略
  • 现代浏览器在安全性和可用性之间选择了一个平衡点。在遵循同源策略的基础上,选择性地为同源策略“开放了后门”。例如img script style等标签,都允许垮域引用资源,然而,你也只能是引用这些资源而已,并不能读取这些资源的内容

同域策略的限制

  • Cookie,LocalStorage和IndexDB无法读取
  • DOM和js对象无法获取
  • AJAX请求无法发送

常见的跨域场景

URL说明是否允许通信
http:/lwww.a.com/a.js ==> http:/lwww.a.com/b.js同一域名下允许
http://www.a.com/lab/a.js ==> http://www.a.com/script/b.js同一域名下不同文件夹允许
http:/www.a.com:8000/a.js ==> http://www.a.com/b.js同一域名,不同端口不允许
http://www.a.com/a.js ==> https://www.a.com/b.js同一域名,不同协议不允许
http://www.a.com/a.js ==> http://70.32.92.74/b.js域名和域名对应ip不允许
http://www.a.com/a.js ==> http://script.a.com/b.js主域相同,子域不同不允许
http:/www.a.com/a.js ==> http://a.com/b.js同一域名,不同二级域名(同上)不允许(cookie这种情况下也不允许访问)不允许
http://www.cnblogs.com/a.js ==> http://www.a.com/b.js不同域名不允许

跨域的解决方案

  • 通过jsonp跨域
  • document.domain + iframe跨域
  • location.hash + iframe
  • window.name + iframe跨域
  • postMessage跨域
  • 跨域资源共享(CORS)
  • nginx代理跨域
  • nodejs中间件代理跨域
  • WebSocket协议跨域

2.1 nginx正向代理与反向代理

正向代理:代理位于网站和客户端中间,客户端无法访问某网站,就将请求发送给代理服务器,代理从网站取回来再发送给客户端,网站并不知道为谁提供服务

反向代理:客户端访问某网站的一个页面,但是网站并没有,就偷偷从另外一台服务器上取回来,然后作为自己的内容吐给用户,用户不知道真正提供服务的是谁

nginx是如何通过反向代理解决跨域的

对于浏览器来说,访问的就是同源服务器上的一个url。而nginx通过检测url前缀,把http请求转发到后面真实的物理服务器。并通过rewrite命令把前缀再去掉。这样真实的服务器就可以正确处理请求,并且并不知道这个请求是来自代理服务器的。

简单说,nginx服务器欺骗了浏览器,让它认为这是同源调用,从而解决了浏览器的跨域问题。又通过重写url,欺骗了真实的服务器,让它以为这个http请求是直接来自与用户浏览器的。

跨域案例演示:

前端代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<button onclick="sendAjax()">跨域请求</button>
<script type="text/javascript">
  var sendAjax = () => {
      var xhr = new XMLHttpRequest();
      xhr.open('GET', 'http://www.blogs-s.com:8080/api/index.php', true);
      xhr.send();
      xhr.onreadystatechange = function (e) {
        if (xhr.readyState == 4 && xhr.status == 200) {
          console.log(xhr.responseText);
        }
      };
  }
</script>
</body>
</html>

测试请求发现出现跨域问题:

对nginx进行代理配置如下:

server
{
    listen 80;
    server_name www.blogs.com;
    root /www/blog;
    index  index.html index.php;

    location /api/ {
       proxy_pass http://www.blogs-s.com:8080/api/;
    }
}

修改html页面中发送请求地址:

http://www.blogs-s.com:8080/api/index.php 修改为 /api/index.php

当客户端请求/api/index.php时,通过nginx将请求发送到 http://www.blogs-s.com:8080/api/ 进行处理。

再次进行测试:

3. nginx缓存

3.1 什么是缓存?

缓存的基本概述

缓存的基本思想是利用客户端访问的时间局限性,将客户端访问过的内容做一个副本,在一定时间内存放到本地,当改数据下次被访问时,不必连接到后端服务器反复去查询数据,而是由本地保存的副本响应数据。

保存在本地的这些副本具有一个过期时间,超过该时间将会更新。判断一个副本数据是否为过期数据的办法有很多,可以使用保留时间来判断,也可以使用数据完整度来判断。

许多Web服务器还具有校验功能,就是当某些副本数据过期以后,先向后端服务器发送校验请求,后端服务器对这些数据进行校验,如果发现原数据和副本没有差别,则将过期副本重新置为可用副本。

缓存的好处

  1. 减轻服务器负载
  2. 提供网页响应效率
  3. 降低网络阻塞,增强网络可扩展性

为什么使用缓存?

  1. 服务器处理能力以及负载能力出现瓶颈,响应效率大大降低
  2. 为了减少网络传输延迟,提升响应效率
  3. 能够避免因为后端服务器出现异常以及网络故障,客户端请求数据副本能够及时响应

3.2 nginx的缓存机制

proxy模块指令

配置块名称名称
httpproxy_cache_path指定缓冲区的路径
levels缓存目录级最高三层,每层1-2个字符表示,比如:1:1:2 三层
keys_zone缓存块名称及内存块大小,比如:cache_item:500m表示声明一个名为cache_item大小为500m,超出大小后最早的被清除
max_size缓存区硬盘的最大值,超出闲置数据将被清除
inactive最长闲置时间,比如:10d ,表示一个数据被闲置10天则将被清除
locationproxy_cache指定缓冲区,对应keys_zone中的设定的值
proxy_cache_key通过参数拼装参数key如:$host$uri$is_args$args 则会已全部md5值作为key
proxy_cache_valid对不同的状态码设置缓存有效期

以上nginx配置结合使用:

http {
  .
  .
  .
  proxy_cache_path /cache/nginx levels=1:2 keys_zone=imooc_cache:10m max_size=5g inactive=60m use_temp_path=off;

  .
  .
  .
  server {
    .
    .
    .
    location /api/ {
      proxy_cache imooc_cache;
      proxy_pass http://www.blogs-s.com:8080/api/;
      proxy_cache_valid 200 304 12h;
      proxy_cache_valid any 10m;
      proxy_cache_key $host$uri$is_args$args;
      include proxy_params;
    }
  }
}

proxy_params文件的配置如下:

proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_buffering on;
proxy_buffer_size 32k;
proxy_buffers 4 128k;

访问一次页面,并向 http://www.blogs-s.com:8080/api/ 发起一个接口数据请求,查看/cache/nginx目录下的缓存结果:

[root@localhost /]# cat /cache/nginx/b/e1/a88f32c1bd828f3a614ab8584c74ae1b
KEY: www.blogs.com/api/index.php
HTTP/1.1 200 OK
Server: nginx/1.18.0
Date: Mon, 22 Mar 2021 16:23:18 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 36
Connection: close
X-Powered-By: PHP/7.4.16

{"message":"this is api","code":304}
[root@localhost e1]#

3.2 清除缓存

ngx_cache_purge介绍

ngx_cache_purge是nginx的第三方模块,能够帮助我清除nginx中的缓存。

在之前的nginx编译安装中我们是没有把缓存的清除模块ngx_cache_purge编译进去的,如果启动了缓存,没有安装这个模块,在之后的调试中我们尝试去清除缓存时,将会出现异常:

2021/03/26 11:17:49 [emerg] 12180#0: unknown directive "proxy_cache_purge" in /vhost/blog.conf:24

这个异常是在指示我们,找不到该指令的驱动,需要按照相关模块。

ngx_cache_purge只是nginx的第三方模块,并不是某个特殊的软件,所以我们需要对nginx重新进行编译,操作如下:

./configure --sbin-path=/usr/local/nginx/nginx --conf-path=/usr/local/nginx/nginx.conf --pid-path=/usr/local/nginx/nginx.pid --with-http_gzip_static_module --with-http_stub_status_module --with-file-aio --with-http_realip_module --with-http_ssl_module --with-pcre=/home/pcre-8.44 --with-zlib=/home/zlib-1.2.11 --with-openssl=/home/openssl-1.1.1g --add-module=/home/ngx_cache_purge-2.3

make -j2

make install

配置nginx:

location ~ /clear_cache(.*) {
     allow   all;
     proxy_cache_purge imooc_cache $host$1$is_args$args;
}

再一次启动nginx成功;

接下来进行缓存清除测试,访问:http://blogs.com/clear_cache/api/index.php, 访问这个连接将会清除接口:http://blogs.com/api/index.php 的缓存数据。

结果如下:

3.3 控制nginx缓存(如何控制nginx缓存什么数据不缓存什么数据?)

在项目开发中,不可能出现什么都需要缓存的数据,缓存仅仅适合去缓存查询频繁,但是不需要实时更新的数据,这个是它适合的场景,而我们上面的配置,只要是访问api接口目录就会缓存接口的数据,这样对于一些需要实时更新的接口数据来说是不合理的,需要控制好nginx的缓存去缓存什么以及不缓存什么

server
{
    .
    .
    .
    location /api/ {
       set $a 0;
       if ( $request_uri ~ /api/noapi/(.*) ){
           set $a 1;
       }

       proxy_no_cache $a;
       .
       .
       .
    }

    location ~ /clear_cache(.*) {
         allow   all;
         proxy_cache_purge imooc_cache $host$1$is_args$args;
    }
}

set 指令为变量设置,proxy_no_cache参数中的值可以设置多个,但是多个值中,只要有一个是不为0的,就会通过缓存响应数据。

proxy_cache指令详解

  1. proxy_cache 指令

该指令用于配置一块公用的内存区域的名称,该区域可以存放缓存的索引数据。这些数据在Nginx服务器启动时由缓存索引重建进程负责建立,在Nginx服务器的整个运行过程中由缓存管理进程负责定时检测过期数据,检索等管理工作。

proxy_cache zone | off;

zone,设置的用于存放缓存索引的内存区域的名称。
off,关闭proxy_cache 功能,是默认的设置。
  1. proxy_cache_bypass指令

该指令用于配置Nginx服务器向客户端发送响应数据时,不从缓存中获取的条件。这些条件支持使用Nginx 配置的常用变量。

proxy_cache_bypass string ..;

string为条件变量,支持设置多个,当至少有一个字符串指令不为空或者不等于О时,响应数据不从缓存中获取。

看一个例子:

proxy_cache _bypass $cookie_nocache $arg nocache $Sarg_comment $http_pragma $http.authorization;

其中,Scookie_nocache、Sarg_nocache、Sarg_comment、Shttp_pragma 和Shttp_authorization 都是Nginx配置文件的变量,

  1. proxy_cache_key指令

该指令用于设置Nginx服务器在内存中为缓存数据建立索引时使用的关键字

proxy cache key string;

string为设置的关键字,支持变量。

如果我们希望缓存数据包含服务器主机名称等关键字,则可以将该指令设置为:

proxy_cache_key "$scheme$host$request";
  1. proxy_cache_lock指令

该指令用于设置是否开启缓存的锁功能。在缓存中,某些数据项可以同时被多个请求返回的响应数据填充。开启该功能后,Nginx服务器同时只能有一个请求填充缓存中的某一数据项,这相当于给该数据项上锁,不允许其他请求操作。其他的请求如果也想填充该项,必须等待该数据项的锁被释放。这个等待时间由 proxy_cache_lock_timeout 指令配置。

proxy_cache_lock on | off;

默认情况下为关闭
  1. proxy_cache_lock_timeout指令

该指令用于设置缓存的锁功能开启以后锁的超时时间。具体细节参见proxy_cache_lock 指令的相关内容

proxy cache_ lock_timeout time;

其中,time为设置的时间,默认为5s。

  1. proxy_cache_min_uses指令

该指令用于设置客户端请求发送的次数,当客户端向被代理服务器发送相同请求达到该指令设定的次数后,Nginx服务器才对该请求的响应数据做缓存。合理设置该值可以有效地降低硬盘上缓存数据的数量,并提高缓存的命中率。

proxy_cache_min_uses number;

其中,number为设置的次数。默认设置为1。

  1. proxy_cache_path指令

该指令用于设置Nginx服务器存储缓存数据的路径以及和缓存索引相关的内容

proxy_cache_path [levels=levels] keys_zone=name:sizel [inactive=time1] [max_size=size2][loader_files=number] [loader_sleep=time2]
[loader_threshold-time3];

path,设置缓存数据存放的根路径,该路径应该是预先存在于磁盘上的。levels,设置在相对于path指定目录的第几级hash目录中缓存数据。
levels=1:表示一级hash目录;levels=1:2,表示两级,依次类推。目录的名称是基于请求URL通过哈希算法获取到的。
name:sizel,Nginx服务器的缓存索引重建进程在内存中为缓存数据建立索引,这一对变量用来设置存放缓存索引的内存区域的名称和大小。
timel,设置强制更新缓存数据的时间,当硬盘上的缓存数据在设定的时间内没有被访问时,Nginx服务器就强制从硬盘上将其删除,下次客户端访问该数据时重新缓存。该指令默认设置为10s。
size2、设置硬盘中缓存数据的大小限制。我们知道,硬盘中的缓存源数据由Nginx服务器的缓存管理进程进行管理,当缓存的大小超过该变量的设置时,缓存管理进程将根据最近最少被访问的策略删除缓存。
number ,设置缓存索引重建进程每次加载的数据元素的数量上限。在重建缓存索引的过程中,进程通过一系列的递归遍历读取硬盘上的缓存数据目录及缓存数据文件,对每个数据文件中的缓存数据在内存中建立对应的索引,我们称每建立一个索引为加载一个数据元素。进程在每次遍历过程中可以同时加载多个数据元素,该值限制了每次遍历中同时加载的数据元素的数量。默认设置为100。
time2,设置缓存索引重建进程在一次遍历结束、下次遍历开始之间的暂停时长。默认设置为50ms.
time3,设置遍历一次磁盘缓存源数据的时间上限。默认设置为200ms

该指令设置比较复杂,一般需要设置前面三个指令的情形比较多,后面的几个变量与Nginx服务器缓存索引重建进程及管理进程的性能相关,一般情况下保持默认设置就可以了。我们来看几个简单的配置实例:

proxy_cache path /nginx/cache/a levels=1 keys_zone=a:10m;
proxy_cache_path /nginx/cache /b levels-2:2 keys_zone=b:100m;
proxy _cache_path /nginx/cache/c levels=1:1:2 keys_zone=c:1000m;
  1. proxy_cache_use_stale指令

如果Nginx在访问被代理服务器过程中出现被代理的服务器无法访问或者访问错误等现象时,Nginx服务器可以使用历史缓存响应客户端的请求,这些数据不一定和被代理服务器上最新的数据相一致,但对于更新频率不高的后端服务器来说,Nginx服务器的该功能在一定程度上能够为客户端提供不间断访问。该指令用来设置一些状态,当后端被代理的服务器处于这些状态时,Nginx服务器启用该功能。

proxy_cache_use_stale error| timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_404 | off..·:

该指令可以支持的状态如语法结构中所示。

  1. proxy_cache_valid指令

该指令可以针对不同的HTTP响应状态设置不同的缓存时间,

proxy_cache_valid [code...] time;

code,设置HTTP响应的状态代码。该指令可选,如果不设置,Nginx服务器只为HTTP状态代码为200、301和302的响应数据做缓存。可以使用“any”表示缓存所有该指令中未设置的其他响应数据。

time,设置缓存时间。看几个例子:
proxy_cache_valid 200 302 10m;
proxy_cache_valid 301 1h;
proxy_cache_valid any 1m;

该例子中,对返回状态为200和302的响应数据缓存10分钟,对返回状态为301的响应数据缓存1小时,对返回状态为非200、302和301的响应数据缓存1分钟。
  1. proxy_no_cache

该指令同于配置在什么情况下不使用cache功能

proxy_no_cache $string...;

string 可以是一个或者都多个变量。当string的值不为空或者不为0时,不启用cache功能
  1. proxy_store 指令

该指令配置是否在本地磁盘缓存来自被代理服务器的响应数据。这是Nginx服务器提供的另一种缓存数据的方法,但是该功能相对 Proxy Cache简单一些,它不提供缓存过期更新、内存索引建立等功能,不占用内存空间,对静态数据的效果比较好。

proxy_store on | off | string;

on | off,设置是否开启Proxy Store功能。如果使用变量on,功能开启,缓存文件会存放到alias指令或root指令设置的本地路径下。默认设置为off。
string,自定义缓存文件的存放路径。如果使用变量string,Proxy Store功能开启,缓存文件会存放到指定的本地路径下。

Proxy Store方法多使用在被代理服务器端发生错误的情况下,用来缓存被代理服务器的响应数据。

  1. proxy_store_access指令

该指令用于设置用户或用户组对Proxy Store缓存的数据的访问权限,

proxy_store_access users:permissions ...

users,可以设置为user、group或者all。
permissions,设置权限。

有关Proxy Store方法的使用,我们通过官方给出的实例加深理解,在该实例中笔者通过注释对配置做了说明:

1ocation /images/
{
  root /data/www;
  error_page 404 = /fetch$uri;      #定义了404错误的请求页面
}

1ocation /fetch/                    #匹配404错误时的请求
{
  proxy_pass http://backend;
  proxy_store on;                   #开启Proxy store方法
  proxy_store_access user:rw group:rw all:r;
  root/data/www;                    #缓存数据的路径
}

添加新评论 »

在这里输入你的评论...