> For the complete documentation index, see [llms.txt](https://yangsx95.gitbook.io/notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://yangsx95.gitbook.io/notes/distributed/web-fu-wu-qi/nginx/jing-tai-zi-yuan-fu-wu-qi-he-dong-jing-fen-li.md).

# 静态资源服务器和动静分离

![1556023839922](/files/hIKfzFzqlgE3DcZLeDjC)

负责接收静态资源请求，根据url从文件存储中获取并返回给客户端，常用于动静分离。

> 静态资源是指无需服务器动态生成的文件资源，比如视频、html、图片等。

**针对静态资源的配置，主要有两个切入点：**

* 针对内容压缩
* 浏览器缓存
* 跨域访问
* 防盗链

## 针对内容压缩

### sendfile、tcp\_nopush、tcp\_nodelay

```nginx
# sendfile，文件零拷贝读取
Syntax: sendfile on|off;
Default: sendfile off;
Context: http, server, location, if in location

# tcp_nopush
# 当使用sendfile时，tcp_nopush才起作用，于tcp_nodelay是互斥的
# 开启后，有数据包不会立即传送出去，而是等到等待传送的数据包达到最大时，一次性传输出去，有利于解决网络阻塞
Syntax: tcp_nopush on|off;
Default: tcp_nopush off;
Context: http, server, location

# tcp_nodelay
# 无等待，立即发送包，在实时性高的情况下可以开启，与tcp_nopush互斥
# 默认开启
# 常用于keepalive 连接下，提高网络包的传输实时性
Syntax: tcp_nodelay on|off;
Default: tcp_nodelay on;
Context: http, server, location
```

### http\_gzip\_static\_module

此模块用于预读gzip压缩文件：

```nginx
location ~ ^/download {
    # 开启此功能
    gzip_static on;
    root /usr/share/nginx/gzipfile;
}
```

在请求`/download/index.html`的时候，此模块会先从root下寻找文件`index.html.gz`，如果找不到才会去寻找`index.html`文件。

gz文件需要预先生成，生成可以使用`gzip`命令：

```shell
gzip ./index.html 
> ls
index.html.gz
```

那么在浏览器请求`/download/index.html`，会展示`index.html.gz`解压后的html文件的内容。

### http\_gunzip\_module

部分浏览器不支持gzip压缩，可以使用此模块，此处不再演示。

### 示例配置

```nginx
server {
    listen       80;
    server_name  116.62.103.228 jeson.imooc.com;
    
    # 打开`sendfile`零拷贝机制
    sendfile on;
    # 多个包打包在一起，一起发送，大文件推荐打开, 可提高网路包的传输效率
    #tcp_nopush on;
    # 实时发送，在是实时性较高的需求中，需要打开（需要连接是keepalived长连接）
    #tcp_nodelay on
    
    #charset koi8-r;
    access_log  /var/log/nginx/log/static_access.log  main;

    # 图片资源匹配
    location ~ .*\.(jpg|gif|png)$ {
        # 打开gzip压缩，发送之前会对资源进行gzip压缩，浏览器接收到时会进行解压，效果可以比对文件传输的大小
        gzip on;
        # gizp的http协议的版本
        gzip_http_version 1.1;
        # 压缩比
        gzip_comp_level 2;
        gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
        root  /usr/share/nginx/img;
    }
	
    # 文本资源匹配
    location ~ .*\.(txt|xml)$ {
        # 文本压缩比图片压缩更有效果
        gzip on;
        gzip_http_version 1.1;
        gzip_comp_level 1;
        gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
        root  /usr/share/nginx/doc;
    }

    # download开头的路径匹配
    location ~ ^/download {
        # 来自 http_gzip_static_module，具有预读gzip功能，需要预先将文件压缩放入磁盘
        gzip_static on;
        tcp_nopush on;
        root /usr/share/nginx/gzipfile;
    }

    #error_page  404              /404.html;
    error_page   500 502 503 504 404  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}
```

## 浏览器缓存

使用浏览器缓存静态资源的两个好处：

* 不用实时从服务器中获取，减少了服务端资源消耗
* 客户端可以从本地直接读取，响应延时更低

### HTTP协议缓存支持

| 功能                                              | Header                 |
| ----------------------------------------------- | ---------------------- |
| HTTP1.0 记录过期时间，超过指定时间会失效                        | Expire                 |
| HTTP1.1 最大期限，用于替代1.0，超过最大期限会失效                  | Cache-Control(max-age) |
| 最后修改时间校验比较，值为时间，只能精确到秒，秒级别的更新无效                 | Last-Modified          |
| 判断Etag是否过期，类似Last-Modified，是一个信息摘要字符串，不同就说明已经过期 | Etag                   |

**Etag 与 Last-Modified 缓存策略下，当缓存处于有效状态时，请求静态资源的响应状态将会变为304。nginx默认采用此种缓存方式**

**Expire与Cache-Control 的优先级大于 Last-Modified 和 Etag**。

第一次请求`admin.html`：![1556090857714](/files/RFCe3QoaHyJTgtIvUwaP)

第二次请求`admin.html`，此时状态已经变为304: ![1556090910417](/files/Ex2ut3jW241ckhHVa1fJ)

### expires 配置浏览器缓存

```nginx
# expires 语句会为响应添加 Cache-Control、Expires头
# time代表缓存时间周期
Syntax: expires [modified] time;
	   expires epoch | max | off;
Default: expires off;
Context: http, server, location, if in location
```

### 示例配置

```nginx
location ~ .*\.(htm|html)$ {
    # 缓存有效期为1天
    expires 24h;
    root /usr/share/nginx/html;
}
```

配置结束后，再次请求静态资源，再次请求`admin.html`： ![1556090998431](/files/Cd5W4bNWOhUY634FtWNN)

此时可以看到，`Cache-Control`已经变为`86400`，单位为秒，即`24h`。

## 跨域访问

浏览器是不允许`ajax`跨域访问，但是`JS`等资源有可能位于CDN中，并且域名不同，此时就需要nginx的跨域访问支持。虽然跨域访问不安全(CSRF攻击)，但是出于软件结构设计、业务形态等种种原因，仍需要跨域访问支持。

### HTTP对跨域的支持

HTTP协议提供了`Access-Control-Allow-Origin`头，此头的值由服务端返回给客户端，告诉客户端可以进行跨站访问。

### 使用add\_header添加跨域头

```nginx
# 给当前响应添加头，name代表头名称，value代表值
Syntax: add_header name value [always];
Default: 
Context: http, server, location, if in location
```

### 示例配置

```nginx
location ~ .*\.(htm|html)$ {
	add_header Access-Control-Allow-Origin http://www.baidu.com;
    # add_header Access-Control-Allow-Origin *; # 所有都可以跨域，会发生CSRF攻击
    add_header Access-Control-Allow-Methods GET,POST,PUT,OPTIONS;
    root /usr/share/nginx/html;
}
```

## 防盗链

防盗链就是防止网站资源被盗用：

* 防止网站资源被爬取
* 大量伪用户访问网站资源，占用网站性能

### 防盗链的设置思路

* 区别哪些请求是非正常用户请求

### 基于http\_refer防盗链

`$http_refer`代表此请求来源处，如果此请求不是本网站的，就不允许访问，这样就能防止其他网站使用自己网站的图片、视频等资源。

```nginx
# 校验refer是否合法，此处可配置多个值，使用空格隔开
# none：允许没有refer信息
# blocked： 允许refer信息不是标准的uri(不是以http://域名开头)
# servernames 允许的ip、域名
# 还支持正则匹配
Syntax: valid_referers none|blocked|servernames|regex ...;
Default: 
Context: server, location
```

### 示例配置

```nginx
# 图片资源匹配
location ~ .*\.(jpg|gif|png)$ {
    gzip on;
    gzip_http_version 1.1;
    gzip_comp_level 2;
    gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
    # 允许请求没有refer信息
    # 允许不标准的refer信息
    # 允许ip为 192.168.173.165 的请求
    # 其他都不允许，返回403
    valid_referers none blocked 192.168.173.165;
    if ($invalid_referer) {
        return 403;
    }
    root  /usr/share/nginx/img;
}
```

## 动静分离

动静分离是指，通过中间件将动态请求与静态请求分离，从而分离资源，减少不必要的请求消耗，减少请求延时。

在动静不分离之前，一个静态请求需要经过一下几个部分才能获取到：

```
中间件(Nginx) -> 程序框架(Spring) -> 程序逻辑 -> 数据资源
```

在东京分离之后，静态请求将会直接由中间件处理，所以效率更高：

```
中间件(Nginx) -> 数据资源
```

并且，如果一方出现问题，另一方不会受到影响。

> 动静分离配置不再演示
