本文目录
跨域配置
动静分离
反向代理-负载均衡
配置SLL证书
资源压缩
缓存机制
IP黑白名单
防盗链
大文件传输优化
跨域问题
产生原因
产生跨域问题的主要原因就在于 「同源策略」 ,为了保证用户信息安全,防止恶意网站窃取数据,同源策略是必须的,否则cookie
可以共享。由于http
无状态协议通常会借助cookie
来实现有状态的信息记录,例如用户的身份/密码等,因此一旦cookie
被共享,那么会导致用户的身份信息被盗取。
同源策略主要是指三点相同,协议+域名+端口 相同的两个请求,则可以被看做是同源的,但如果其中任意一点存在不同,则代表是两个不同源的请求,同源策略会限制了不同源之间的资源交互。
解决跨域问题
- 方式一:直接在 nginx 配置文件的服务 server 模块中适当添加如下内容(然后重启生效)
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';
# 一定要有!!!否则Post请求无法进行跨域!
# 在发送Post跨域请求前,会以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;
}
}
- 方式二:后端代码中配置,以 golang 语言的 Gin 框架中间件包增加如下示例
package middleware
import (
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
)
func Cors() gin.HandlerFunc {
config := cors.DefaultConfig()
config.AllowAllOrigins = true
return cors.New(config)
}
func CORS() gin.HandlerFunc {
return func(c *gin.Context) {
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, DELETE")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
}
}
动静分离
动静分离应该是听的次数较多的性能优化方案,首先需要知道为啥要动静分离
我们部署 web 网站时都会将静态文件一起打包,跟随项目部署到服务某个目录,一般我们都会把这些文件放到项目根目录的 static 目录下,这些文件是大概率不会有太大变动的。当我们访问前端页面,刚开始加载的时候都会有大量请求加载各种静态资源文件,比如 html/js/css/image等等。
比如上图百度首页,就会有至少100+的请求静态资源,那么这些请求都会来到部署WEB
服务的机器处理,那则代表着一个客户端请求百度首页,就会对后端服务器造成100+
的并发请求,毫无疑问,这对于后端服务器的压力是尤为巨大的。
所以想办法在此之前就提前处理掉,因此有了「「动静分离」」 而且 至少能够让后端服务减少一半以上的并发量。
实现方式如下,需要在 Nginx 配置下添加一条 location 规则
location ~ .*\.(html|htm|gif|jpg|jpeg|bmp|png|ico|txt|js|css){
root /soft/nginx/static_resources; #静态资源存放目录
expires 7d;
}
该配置表示匹配以.html~.css为后缀的所有资源请求
~
代表匹配时区分大小写.*
代表任意字符都可以出现零次或多次,即资源名不限制\.
代表匹配后缀分隔符.(html|...|css)
代表匹配括号里所有静态资源类型
反向代理-负载均衡
为啥要用负载均衡
- 单体结构无法承载日益增长的请求量
- 当单体节点宕机后,整个系统会挂掉
因此引入负载均衡,它有以下优势
- 「高可用:」 当某个节点宕机后可以迅速将流量转移至其他节点
- 「高性能:」 多台服务器共同对外提供服务,为整个系统提供了更高规模的吞吐
- 「拓展性:」 当业务再次出现增长或萎靡时,可再加入/减少节点,灵活伸缩
Nginx
是目前负载均衡技术中的主流方案,是基于多路复用模型,主要就是【资源占用少、并发支持高】
原本客户端是直接请求目标服务器,由目标服务器直接完成请求处理工作,但加入Nginx
后,所有的请求会先经过Nginx
,再由其进行分发到具体的服务器处理,处理完成后再返回Nginx
,最后由Nginx
将最终的响应结果返回给客户端。
下面是一个负载均衡的配置示例
upstream nginx_server{
# 请求分发权重比为1:2 30s内检查心跳发送两次包,未回复就代表该机器宕机,
server 192.168.1.000:8001 weight=100 max_fails=2 fail_timeout=30s;
server 192.168.1.000:8002 weight=200 max_fails=2 fail_timeout=30s;
}
server {
listen 80;
location / {
root html;
index index.html index.htm
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 请求交给名为nginx_server的upstream上
proxy_pass http://nginx_server;
}
}
配置 SLL 证书
一般网站都会接入HTTPS
,因此Nginx
还需要监听443
端口的请求,HTTPS
为了确保通信安全,所以服务端需配置对应的数字证书,当项目使用Nginx
部署时,那么证书在Nginx
中也需要有相应的配置,
SSL
证书配置步骤
- 先去CA机构或从云控制台中申请对应的
SSL
证书,审核通过后下载Nginx
版本的证书 - 下载数字证书后,完整的文件总共有三个:
.crt、.key、.pem
: .crt
:数字证书文件,.crt
是.pem
的拓展文件,因此有些人下载后可能没有。.key
:服务器的私钥文件,及非对称加密的私钥,用于解密公钥传输的数据。.pem
:Base64-encoded
编码格式的源证书文本文件,可自行根需求修改拓展名。
最后添加 nginx 配置,如下所以,然后重启访问:https:localhost 查看是否生效
server {
listen 80;
# 添加监听 https 端口
listen 443 ssl;
server_name localhost;
# 根目录
location / {
# vue项目的打包后的dist
root /webapp/dist;
index index.html index.htm;
}
# 填写证书文件的相对路径或绝对路径
ssl_certificate /webapp/ng_https/xxx.crt;
# 填写私钥文件的相对路径或绝对路径
ssl_certificate_key /webapp//ng_https/xxx.key;
ssl_session_timeout 5m;
#请按照以下协议配置
ssl_protocols TLSv1.2 TLSv1.3;
#请按照以下套件配置,配置加密套件,写法遵循 openssl 标准。
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
# 下面是强制 https 访问方式,按需打开
#rewrite ^(.*)$ https://$host$1 permanent;
}
资源压缩
在动静分离的基础之上,如果一个静态资源的Size
越小,那么自然传输速度会更快,同时也会更节省带宽,因此我们在部署项目时,也可以通过Nginx
对于静态资源实现压缩传输
- 一方面可以节省带宽资源
- 第二方面也可以加快响应速度并提升系统整体吞吐
在Nginx也提供了三个支持资源压缩的模块 ngx_http_gzip_module、ngx_http_gzip_static_module、ngx_http_gunzip_module,其中 ngx_http_gzip_module 属于内置模块,代表着可以直接使用该模块下的一些压缩指令,后续的资源压缩操作都基于该模块,压缩配置的一些参数/指令如下
参数项 | 释义 | 参数值 |
---|---|---|
gzip | 开启或关闭压缩机制 | on/off: |
gzip_types | 根据文件类型选择性开启压缩机制 | image/png、 text/cs5... |
gzip_comp_level | 用于设置压缩级别,级别越高越耗时 | 越高压缩效果越好 |
gzip_vary | 设置是否携带Vary:Accept-Encoding头域的响应头部 | on/off |
gzip_buffers | 设置处理压缩请求的缓冲区数量和大小 | 数量大小,如16 8k |
gzip_disable | 针对不同客户端的请求来设置是否开启压缩 | 如.*Chrome.*; |
gzip_http_version | 指定压缩响应所需要的最低HTTP请求版本 | 如1.1; |
gzip_min_length | 设置触发压缩的文件最低大小 | 如512k |
gzip_proxied | 对于后端服务器的响应结果是否开启压缩 参数值 | off、expired、no-cach |
如下是Nginx
中的压缩配置示例
http{
# 开启压缩机制
gzip on;
# 指定会被压缩的文件类型
gzip_types text/plain application/javascript text/css application/xml text/javascript image/jpeg image/gif image/png;
# 设置压缩级别,越高资源消耗越大,但压缩效果越好
gzip_comp_level 5;
# 在头部中添加Vary: Accept-Encoding(建议开启)
gzip_vary on;
# 处理压缩请求的缓冲区数量和大小
gzip_buffers 16 8k;
# 对于不支持压缩功能的客户端请求不开启压缩机制
gzip_disable "MSIE [1-6]\."; # 低版本的IE浏览器不支持压缩
# 设置压缩响应所支持的HTTP最低版本
gzip_http_version 1.1;
# 设置触发压缩的最小阈值
gzip_min_length 2k;
# 关闭对后端服务器的响应结果进行压缩
gzip_proxied off;
}
- 对于图片、视频类型的数据,会默认开启压缩机制,因此一般无需再次开启压缩
- 对于.js文件而言,需要指定压缩类型为application/javascript,而并非text/javascript、application/x-javascript。
缓存机制
对于性能优化而言,缓存是一种能够大幅度提升性能的方案,因此几乎可以在各处都能看见缓存,如客户端缓存、代理缓存、服务器缓存等等,Nginx
的缓存则属于代理缓存的一种,它包含以下优势
- 减少向后端或文件服务器请求资源的带宽消耗
- 降低了下游服务器的访问压力,提升系统整体吞吐
- 缩短了响应时间,提升了加载速度,打开页面的速度更快
在Nginx
中,配置代理缓的配置项:(如下示例)
「proxy_cache_path」:代理缓存的路径
http {
proxy_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time];
}
参数含义
path
:缓存的路径地址。levels
:缓存存储的层次结构,最多允许三层目录。use_temp_path
:是否使用临时目录。keys_zone
:指定一个共享内存空间来存储热点Key(1M可存储8000个Key)。inactive
:设置缓存多长时间未被访问后删除(默认是十分钟)。max_size
:允许缓存的最大存储空间,超出后会基于LRU算法移除缓存,Nginx会创建一个Cache manager的进程移除数据,也可以通过purge方式。manager_files
:manager进程每次移除缓存文件数量的上限。manager_sleep
:manager进程每次移除缓存文件的时间上限。manager_threshold
:manager进程每次移除缓存后的间隔时间。loader_files
:重启Nginx载入缓存时,每次加载的个数,默认100。loader_sleep
:每次载入时,允许的最大时间上限,默认200ms。loader_threshold
:一次载入后,停顿的时间间隔,默认50ms。purger
:是否开启purge方式移除数据。purger_files
:每次移除缓存文件时的数量。purger_sleep
:每次移除时,允许消耗的最大时间。purger_threshold
:每次移除完成后,停顿的间隔时间。
「proxy_cache」:开启或关闭代理缓存,开启时需要指定一个共享内存区域。
以上 是Nginx
中的缓存配置项,下面来配置一下Nginx
代理缓存
http{
# 设置缓存的目录,并且内存中缓存区名为hot_cache,大小为128m,
# 三天未被访问过的缓存自动清楚,磁盘中缓存的最大容量为2GB。
proxy_cache_path /log/nginx/cache levels=1:2 keys_zone=hot_cache:128m inactive=3d max_size=2g;
server{
location / {
# 使用名为nginx_cache的缓存空间
proxy_cache hot_cache;
# 对于200、206、304、301、302状态码的数据缓存1天
proxy_cache_valid 200 206 304 301 302 1d;
# 对于其他状态的数据缓存30分钟
proxy_cache_valid any 30m;
# 定义生成缓存键的规则(请求的url+参数作为key)
proxy_cache_key $host$uri$is_args$args;
# 资源至少被重复访问三次后再加入缓存
proxy_cache_min_uses 3;
# 出现重复请求时,只让一个去后端读数据,其他的从缓存中读取
proxy_cache_lock on;
# 上面的锁超时时间为3s,超过3s未获取数据,其他请求直接去后端
proxy_cache_lock_timeout 3s;
# 对于请求参数或cookie中声明了不缓存的数据,不再加入缓存
proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;
# 在响应头中添加一个缓存是否命中的状态(便于调试)
add_header Cache-status $upstream_cache_status;
}
}
}
IP黑白名单
当我们需要指定、或者禁止某些 ip 访问服务时(黑白名单机制),可以通过 nginx 来限制访问,主要是通过allow、deny
配置项来实现
- 单个 ip 可以直接写在 location 里面
server{
location ^~ /my_api/ {
deny 192.177.12.222; # 屏蔽192.177.12.222访问
deny 127.0.0.0/8; # 屏蔽127.0.0.1到127.255.255.254网段中的所有IP访问
allow 192.177.44.201; # 允许192.177.44.201访问
allow 127.45.0.0/16; # 允许127.45.0.1到127.45.255.254网段中的所有IP访问
deny all; # 除开上述IP外,其他IP全部禁止访
}
}
- 批量限制 ip 时,需要新建 .conf 文件来引入
白名单文件 /webapp/white.conf 如下
allow 192.177.12.222; # 允许192.177.12.222访问
allow 192.177.44.201; # 允许192.177.44.201访问
allow 127.45.0.0/16; # 允许127.45.0.1到127.45.255.254网段中的所有IP访问
deny all; # 除开上述IP外,其他IP全部禁止访问
黑名单文件 /webapp/black.conf 如下
deny 192.177.12.222; # 屏蔽192.177.12.222访问
deny 192.177.44.201; # 屏蔽192.177.44.201访问
deny 127.0.0.0/8; # 屏蔽127.0.0.1到127.255.255.254网段中的所有IP访问
然后在 nginx 配置文件中引入
http{
# 屏蔽该文件中的所有IP
include /webapp/black.conf;
server{
location xxx {
# 某一系列接口只开放给白名单中的IP
include /webapp/white.conf;
}
}
}
tips:同时也可以通过ngx_http_geo_module、ngx_http_geo_module
第三方库去实现(这种方式可以按地区、国家进行屏蔽,并且提供了IP
库)
防盗链
含义:指外部网站引入当前网站的资源对外展示
比如 aaa.com 战点的图片资源,在bbb.com站点上面提供给其他人访问
Nginx
的防盗链机制跟头部字段Referer
有关,该字段描述了当前请求是从哪儿发出的,那么在Nginx
中就可通过判断是否为本站的资源发起的请求,如果不是则不允许访问。
利用 Nginx
配置项 中的valid_referers
实现防盗链功能,示例配置如下
# 在 location 中开启防盗链机制
location ~ .*\.(html|htm|gif|jpg|jpeg|bmp|png|ico|txt|js|css){
# 最后面的值在上线前可配置为允许的域名地址
valid_referers blocked 111.111.111.111;
if ($invalid_referer) {
# 可以配置成返回一张禁止盗取的图片
# rewrite ^/ http://xx.xx.com/NO.jpg;
# 也可直接返回403
return 403;
}
root /soft/nginx/static_resources;
expires 7d;
}
大文件传输优化
web 开发中经常会遇到一些文件的上传下载,文件小的时候没啥问题,正常处理,但是当文件大传输时往往都会会出现一些Bug
,比如文件超出限制、文件传输过程中请求超时等,此时通过Nginx
稍微做一些配置,相关配置项及含义如下
配置项 | 释义 |
---|---|
client max body_size | 设置请求体允许的最大体积 |
client header_timeout | 等待客户端发送一个请求头的超时时间 |
client_body_timeout | 设置读取请求体的超时时间 |
proxy_read timeout | 设置请求被后端服务器读取时,ginx等待的最长时间 |
proxy_send timeout | 设置后端向Nginx返回响应时的超时时间 |
根据自己的环境、硬件进行相应配置就OK