作者:ThinkStu
一、简介
-
Nginx 是什么?
-
Nginx 的不同版本:
-
yum安装
yum -y install Nginx
-
常用指令
Nginx # 启动 Nginx -v # 查看版本号 Nginx -V # 查看已安装模块 Nginx -t # 测试(常在修改配置文件后使用) Nginx -h # 显示帮助文档 ps -ef | grep Nginx # 查看启动进程 Nginx -s stop # 强制停止 Nginx -s quit # 安全停止 Nginx -s reload # 重新加载配置(主进程不变,工作进程平滑重启)
-
配置文件架构
. 全局配置 |-- event |-- http |-- server |-- location
-
常用 include 全局配置引入其他配置文件:
include /usr/share/Nginx/modules/*.conf;
-
语法规范:所有语句均以分号
;
结尾。 -
工作特点
存在主线程与工作进程之分,master进程指挥 worker 进程工作,worker进程数常与服务器核心数一致,可设为 auto 。
- master进程
- worker进程
> ps -ef|grep Nginx root 1627 1 0 03:10 ? 00:00:00 Nginx: master process Nginx Nginx 1628 1627 0 03:10 ? 00:00:00 Nginx: worker process Nginx 1629 1627 0 03:10 ? 00:00:00 Nginx: worker process
# 全局配置 worker_processes auto;
-
服务器权限控制
user Nginx;
ps -ef |grep Nginx root 954 1 Nginx: master process /usr/sbin/Nginx Nginx 89135 954 Nginx: worker process
-
Host请求头诠释:
-
Host 是 HTTP/1.1 协议中唯一必须携带的请求头,如果缺失就会返回 400 状态码( curl 等操作中默认携带)。
-
作用:指明请求服务器的域名/IP地址和端口号。
-
组成:域名+端口号,如 test.com:1998 。
-
在 HTTP/2 以及 HTTP/3 中,以伪头
:authority
代替。
-
-
常见服务器扩容方式:
- 垂直扩容:硬件设备物理扩容。
- 水平扩容:使用多台提供相同内容的服务器(集群化)。
- 分布式扩容:动静分离、服务分离。
三种扩容方式并没优劣之分,实际使用中依据情况而进行选择、优化。
-
动静分离思想:
- 静态资源放在 Nginx 服务器。
- 动态请求由其他服务器处理(例如 Tomcat )。
-
其他注意点
-
架构图:Nginx + Tomcat 是一套流行的前后端分离架构。
-
keepalived 说明:
keepalived 首先要求使用者申请一个公网 IP 地址,然后将域名绑定到该公网 IP( IP 实际上与机器的 mac 地址相绑定)。该公网 IP 在 keepalived 的加持下可以在多台机上的 mac 上“漂移”,从而实现高可用!
二、常用配置
一些简单的配置
1、listen
监听指定 ip 端口
listen 127.0.0.1:8000;
listen 127.0.0.1; # 监听指定 ip 所有端口
listen 8000; # 监听指定端口(常用)
listen *:8000; # 通配符,同上
server {
# 监听多个端口
listen 443 ssl http2;
listen [::]:443 ssl http2;
listen 80;
listen 81;
server_name example.com ;
}
2、server_name
-
简介
- 配置域名
- 适用通配符
*
(但只能用在开头结尾,不能用于中间) - 适用正则表达式(波浪线
~
开头标识)
-
匹配优先级(高到低)
- 准确匹配
- 通配符匹配
- 正则表达式匹配
-
范例
server_name www.baidu.com; server_name *.baidu.com; server_name www.baidu.*; server_name ~^www\.\w+\.com$; # 正则表达式: www 开头,com 结尾
server { listen 80; server_name www.thinkstu.com; }
3、location
-
支持多种匹配模式。
-
匹配优先级:
- 准确匹配:
=
- 正则前缀匹配:
^~
- 前缀匹配:
/abc
- 正则匹配:
~
、~*
(区分、不区分大小写) - 通用匹配:
/
(注意:当同级匹配冲突时,首先依据长度优先、其次依据匹配次序优先)
- 准确匹配:
-
匹配优先级规则:
- 判断精准命中
- 判断正则前缀匹配
- 判断普通命中。如果有多个命中,取最长的匹配
- 判断正则表达式,由上到下开始匹配**(一旦匹配成功1个,立即返回结果并结束,所以正则需要注意放置顺序)**。
- 判断通用匹配
/
-
范例
location / {} location /abc {} location =/abc {} location ~ /abc {} location ^~ /abc {}
-
匿名location:
# 404状态码转为200,表示错误已处理并返回 @error 内容 error_page 404 =200 @error; location @error{ return 503 "{'msg':'error'}"; # 状态码冲突时,此处失效、error_page优先 # rewrite ^(/.*)$ http://$host/ permanent; }
-
=[response]
更改响应码。 -
编写格式:等号前有空格、后无空格。
-
-
**小tips:**精确匹配初始域名,加快解析速度
location = / { }
4、sendfile
5、nodelay/push
必须开启 sendfile 才能使用 nodelay 与 nopush
-
tcp_nodelay:(默认开启)接收到请求后立即向服务器转发,速度快、资源利用率差。
-
tcp_nopush:接收到请求后缓冲再向服务器转发,速度慢、资源利用率高。
-
nopush 与 nodelay 共同使用:
-
Linux V2.5.9 允许,它能够极大提升效率。
-
在正常情况下使用 nopush 传输数据。
-
当碰上最后一次传输数据时,使用 nodelay 直接传送(避免缓冲区不满导致空转)。
> uname -a Linux VM-12-16-centos 3.10.0-1160.76.1.el7.x86_64
-
6、add_header
-
作用:添加 http 请求头。
-
表示形式:键值对,可选用 always 表示无论浏览器是否支持、总是配置。
add_header key value [always];
add_header cache-control max-age=600;
7、set 变量
简介:Nginx 中设置,使用变量时携带美元 $
符号。
location /test {
set $abc '123';
return 200 $abc;
}
8、if
-
简介:与编程 if 语句大致类似
-
语法规则:
- if 与括号之间加空格
- if 不能直接判断变量,必须借助“中间参数”
-
判断条件:
- 空、 0 表示 false。
- = 、 != 比较变量与字符串是否相等。
-f 和 !-f 用来判断是否存在文件 -d 和 !-d 用来判断是否存在目录 -e 和 !-e 用来判断是否存在文件或目录 -x 和 !-x 用来判断文件是否可执行
location /test { default_type text/plain; set $abc ''; if ($abc){ return 403; } return 200; }
-
对图片文件判断 并 设置过期时间(可用于反向代理配置中,优化逻辑)
if ($uri ~ ^.*\.(png|jpg|jpeg|gif)$){ expires 3600; }
-
简单范例:
- 判断请求是否存在参数
- 判断请求文件是否存在:
-f
- 判断是否包含指定字符:正则表达式
if ($args){} if (-f $request_filename){} if ($http_user_agent ~ Safari) # 正则 if ($http_user_agent !~ Safari) # 取反 if ($http_user_agent ~* Safari) # 不区分大小写
9、return
-
简介:
-
简单使用
location /test { return https://thinkstu.com/; # return 302 https://thinkstu.com/; # return 301 https://thinkstu.com/; }
10、keepalive
尚需大量实践
- 两种不同的类型
- TCP keepalive
- Http keealive
- Nginx配置 keepalive:
# 时间为 0 表示关闭 keepalive
keepalicve_timeout 0s;
keepalicve_timeout 65s;
# 单个连接中可处理的请求数量
# 表示不与某些浏览器建立长连接
# 最长连接时间(超过强制关闭)
keepalive_request 1000;
keepalive_disable msie6;
keepalive_time 1h;
send_timeout: 120s;
- 反向代理与 keepalive:
keepalive 100;
keepalive_timeout 65s;
keepalive_request 1000;
proxy_http_version 1.1;
proxy_set_header Connnection " ";
三、常用操作
1、Gzip压缩
宝塔面板默认配置
-
简介
-
常用配置
gzip on; # 开启(默认关闭) gzip_min_length 1k; # 最小压缩限值,建议 1KB gzip_comp_level 2; # 压缩等级1-9,动态设置考虑性能比 gzip_min_length 1kb; # 最小压缩启动值 gzip_buffers 4 16k; # 默认,无需配置 gzip_http_version 1.1; # 默认 1.1,无需配置 gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml text/html; # 压缩类型 gzip_vary on; # header标识:告知浏览器使用 gzip 压缩 gzip_disable "MSIE [1-6]\."; # 排除旧版本浏览器,支持正则表达式 gzip_proxied expired no-cache no-store private auth; # 反向代理时设置
-
gzip_proxied:作为反向代理时使用,表示是否对服务端返回的结果进行 gzip 压缩,参数表示浏览器作出相应表示时才启动。
gzip_proxied expired no-cache no-store private auth;
-
-
gzip_static插件:
2、正则表达式
- 正则规则
-
Nginx使用
-
~
:严格正则,区分大小写 -
~*
:宽松正则,不区分大小写 -
^~
:前缀正则,如果匹配到则直接返回。 -
!~
:严格正则取反。 -
!~*
:宽松正则取反。
-
3、rewrite重写
-
简介:重写 url 使请求重定向,浏览器发送2次请求。
-
规则:
- 只能在 server、location 块与 if 语句中使用。
- 只对域名后边的除去传递参数的字符起作用。
# 对 https://a.com/1/11010.json?b=10 而言仅 /1/11010.json 可重写。
-
正则延伸:
-
^/
:匹配全部 -
^(/.*)$
:匹配全部,后用$1
承接。
-
-
重写标志位:标识重写方式
-
常用变量:rewrite 使用 Nginx 全局参数。
变量 说明 $request_uri 变量中存储了当前请求的URI,并且携带请求参数。 $args url请求参数 $uri 获取 uri $document_uri 功能和 $uri 一样 $host 服务器 server_name 值 $http_user_agent 浏览器代理信息 $document_root 请求对应的root目录,未设置则指向Nginx自带html目录 $content_length Content-Length $content_type Content-Type $http_cookie cookie $limit_rate 存储服务器对网络连接速率的限制,默认0不限制。 $remote_addr 客户端 IP 地址 $remote_port 客户端与服务端建立连接的端口号(指客户端的) $remote_user 存储客户端的用户名,需要有认证模块才能获取 $scheme 访问协议,如http $server_addr 服务端的地址 $server_name 客户端请求到达的服务器的名称 $server_port 客户端请求到达服务器的端口号 $server_protocol 存储客户端请求协议的版本,如"HTTP/1.1" $request_body_file 存储发给后端服务器的本地文件资源的名称 $request_method 存储客户端的请求方式,比如"GET","POST"等 $request_filename 存储当前请求的资源文件的路径名 -
rewrite_log 日志:该指令用来指明是否开启 URL 重写日志输出功能,开启后将以 notice 级别向 error.log 日志中输出信息(配置相应 error 日志文件中的输出级别为 notice ,这将会输出大量日志记录),不建议使用该功能。
location /test { rewrite ^(/.*)$ https://$host$1 permanent; rewrite_log on; #开启 error_log /var/log/Nginx/error.log notice; }
4、rewrite范例
-
强制HTTPS
if ($server_port !~ 443){ rewrite ^(/.*)$ https://$host$1 permanent; # 永久重定向 }
-
目录对换
/123456/xxxx -> /xxxx?id=123456 rewrite ^/(\d+)/(.+)/ /$2?id=$1 last;
-
指定浏览器对换指定路径
location / { if ( $http_user_agent ~* MSIE ){ #ie浏览器使用此url资源 rewrite ^(.*)$ /msie/$1 break; } if ( $http_user_agent ~* chrome ){ #谷歌浏览器使用此url资源 rewrite ^(.*)$ /chrome/$1 break; } }
-
将
a.com/b
跳转至b.a.com
rewrite ^/b$ http://b.a.com permanent; rewrite ^/b/(.*)$ http://b.a.com/$1 permanent;
-
a.com
跳转到www.a.com
if ($host = 'a.com' ) { rewrite ^/(.*)$ http://www.a.com/$1 permanent; }
-
指定页面返回404
# /a/数字.htmlb rewrite ^/a/([0-9]+)\.html$ /404.html last;
5、跨域
-
简介:
-
理解参考文献:
-
CSRF理解:
-
利用请求头允许跨域:
即跨域会自动发送 Origin 请求头,服务器设置 Allow-Origin 链接与请求方式。
add_header Access-Control-Allow-Origin http://unMeta.cn; add_header Access-Control-Allow-Methods GET,POST;
6、防盗链
valid_referers 与 $invalid_referer 结合使用
-
简介:
-
三种情景发送【referer】:
<img src="foo.jpg"> <script src="foo.js"></script> <link href="foo.css" rel="stylesheet">
-
不发送 referer 的两种原生方法:
-
rel:a、area 和 form 三个标签可以使用
rel="noreferrer"
属性,一旦使用,该元素就不会发送Referer字段,但是 rel 局限只能单个设置。<a href="..." rel="noreferrer" target="_blank">点击按钮</a>
-
Referrer Policy:更为强大的 w3c 标准,可应用 3 种场景、 8 种模式,常用2种模式(origin、no-referrer,发送与不发送)。
Referrer-policy: no-referrer
<Meta name="referrer" content="origin">
<img src="..." referrerpolicy="origin">
-
-
- none:如果 referer 为空,允许访问。
- blocked:如果请求头中的 referer 不为空,则允许不带“http://”、“https://”等协议头访问。
- 具体的域名或 IP 。
location ~ .*\.(css|js|png|jpg|jpeg)$ { root /usr/share/Nginx/html/images; # 只允许空 referer 与 thinkstu.com 进行跳转访问 valid_referers none thinkstu.com; # 若为 true,即 “无效的referer” 成立,返回 403 Forbidden 标识 if ($invalid_referer){ return 403; } }
if ($invalid_referer){ rewrite ^/ /2.jpg break; }
7、适配移动设备
适配移动端/桌面端设备
-
借助开源脚本:国外 detect mobile browsers
-
源码详解:
# 设置变量:mobile_rewrite = 非移动端 set $mobile_rewrite do_not_perform; # 如果是移动端的话:mobile_rewrite = 移动端 if ($http_user_agent ~* "是移动端") { set $mobile_rewrite perform; } # 判断是否为移动端,进行相应操作 if ($mobile_rewrite = perform) { rewrite ^(/.*)$ http://mobile.网址.com/$1 redirect break; # 或者更改 root 目录 # root /html/mobile; }
8、获取 IP 地址
-
获取 IP 地址主要分为两种情况:
-
因为后端服务器接收到的“网际层面IP地址”永远只能是 Nginx 服务器的 IP 地址。
-
Nginx设置IP转发头:
proxy_set_header x_forwarded_for $remote_addr;
-
如何防止前端伪造 IP 请求头?
只要我们在配置中设置了 x_forwarded_for ,就会自动覆盖掉用户写的 x_forwarded_for ,以此来达到目的。
# 覆盖用户私自声明的 x_forwarded_for proxy_set_header x_forwarded_for $remote_addr;
-
如何避免多级 Nginx 链重写 x_forwarded_for 请求头?
9、乱码修复
server 与 location 中均可配置。
server {
# ...
charset utf-8;
}
10、简易下载站点
-
简介:将服务器上的某目录开放访问,点击下载。
-
4个配置:
- autoindex:为 on 时,访问目录中会生成目录列表,点击下载。
- autoindex_exact_size:是否精确显示。
- autoindex_format:可选 html/json/jsonp/xml,默认 html(点击下载)。
- autoindex_localtime:
autoindex on; autoindex_exact_size off; autoindex_format html; autoindex_localtime on;
-
简易下载站
# 地址最后带有斜杆,表示访问目录 location =/test/ { autoindex on; autoindex_exact_size off; autoindex_format html; autoindex_localtime on; } # 正则匹配,声明强制下载 location ~* ^/test/.*$ { add_header Content-disposition "attachment;"; }
11、禁止访问
返回 403 Forbidden 状态码
即可以使用 deny 实现,也可以使用 allow 实现
-
简介:
-
简单配置(allow相同)
deny all; deny 127.0.0.1; deny 123.1.1.0/24; # 123.1.1.1 ~ 123.1.1.254
-
叠加 limit_except语法进行配置:
limit_except GET { allow 192.168.1.0/32; deny all; }
- location块中使用
- method 参数可以是 GET、HEAD、POST、PUT、DELETE 等。
- 允许 GET 也将使 HEAD 被允许。
-
范例:
location ~/\.ht { deny all; # 善用 deny all; }
location ~ ^/(cron|templates)/ { deny all; }
12、root目录
通过更改 root 根目录实现:重定向资源访问路径
location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ {
root /webroot/res/;
}
13、 压测工具
Apache压测工具: httpd-tools
yum install httpd-tools
ab -n 1000 -c 30 https://baidu.com/
14、简易登录验证
-
简介:小型化认证工具,明文传输、易受攻击。
-
使用流程:
-
yum install httpd-tools
# 创建一个新文件记录用户(回车输入密码) htpasswd -c /usr/local/Nginx/conf/htpasswd username # 追加一个用户 htpasswd -b /usr/local/Nginx/conf/htpasswd username password # 删除一个用户 htpasswd -D /usr/local/Nginx/conf/htpasswd username # 验证一个用户的账号密码 htpasswd -v /usr/local/Nginx/conf/htpasswd username
-
Nginx配置:
- 设置备注信息,备注信息是否显示与浏览器版本有关;
- 备注信息可以为空但是必须要设置,否则无法开启验证模式。
auth_basic "请输入账号密码"; auth_basic_user_file /usr/share/Nginx/users/login_01;
15、快速返回
利用 return 语句
-
实现:server、location中均可使用。
location / { default_type text/JSON; charset utf-8; return 200 "{'msg':'ok'}"; }
16、错误页面
error_page
error_page 404 =302 http://a.com;
error_page 404 =200 /index.html; # 这里虽然标识为200,但是依旧会返回302进行重定向
error_page 404 =200 '{'code':'200','msg':'error'}';
17、宝塔说明
-
简介:
-
架构:
-
/www/backup/file_history/www/server/panel/vhost/Nginx/java_emptyForward-0.conf
18、隐藏版本号
Nginx 服务器在返回的响应头中包含版本信息,而某些版本可能存在漏洞,为防止其他人利用版本漏洞进行攻击,我们可以选择不返回版本信息。
server_tokens off;
19、浏览器接收类型
-
简介:
- 其实就是定义服务器的返回数据类型,即浏览器接收到的数据类型。
- 可以在 http 或 server、location 中配置。
Content-Type: text/html; charset=utf-8
-
优先级(从上至下):
-
简单实现:
location / { default_type application/octet-stream; }
location / { add_header Content-disposition "attachment;"; # add_header Content-Type 'text/plain; charset=utf-8';; }
20、模块编译
由于一些环境因素,后续我可能还会回到这
-
简介:
- 必须要掌握的技能。
- 编译安装新模块的时候,必须要把旧的模块参数带上,否则原配置会被覆盖。
-
流程
./configure --prefix=/usr/local/Nginx --with-http_stub_status_module --with-http_ssl_module --with-http_realip_module --with-http_image_filter_module --without-http_rewrite_module
make
cp new__ old__
21、Range
断点续传
-
Range请求头格式(单位默认字节):
Range: bytes=0-10
-
add_header Content-type application/octet-stream;
-
反向代理时关闭 Range
# 覆盖用户 range 请求头,范围超过原文件字节大小即可。 # accept-ranges其实没用,放在这里只是为了提示用户。 add_header Accept-Ranges none; proxy_set_header range 'bytes=0-10000000000';
-
转发请求头至Tomcat:正常情况下无需配置,但发现 range 未生效时可配置。
proxy_set_header Range $http_range;
四、缓存
1、web缓存作用于浏览器
2、代理缓存作用于代理服务器
1、web缓存
深入理解浏览器缓存:传送门
-
简介:
- Nginx 实现 web 缓存主要依赖浏览器缓存,数据缓存在客户端。
- 304状态码表示使用缓存。
-
2种缓存类型
- 强缓存:直接获取本地缓存,不向服务器发送任何信息(expires与Cache-Control)。
- 弱缓存:先向服务器发送请求确认缓存是否有效,有效则用、无则请求更新(last-modified与eTag)
-
浏览器缓存响应图
-
Cache-Control请求头参数
指令 说明 must-revalidate 可缓存但必须再向服务器进行确认 no-cache 缓存前必须确认其有效性 no-store 不缓存任何请求 no-transform 代理不可更改媒体类型 public 浏览器、代理服务器均可缓存 private 浏览器可以缓存、代理服务器不可缓存(默认取值) proxy-revalidate 要求中间缓存服务器对缓存的响应有效性再进行确认 max-age=[秒] 缓存有效期 s-maxage=[秒] 公共缓存服务器响应的最大 Age 值 -
expires 与 Cache-Control: max-age=1000 区别:
- expires:http 1.0 协议,兼容老系统。
- max-age:最新标准。如果设置了此,则会忽略 expires。
Expires 缺点: 返回的到期时间是服务器端的时间。存在问题:如果客户端的时间与服务器的时间相差很大,那么误差就很大,所以在HTTP 1.1版开始,使用Cache-Control: max-age=秒替代(相对时间)。
-
实例:缓存 js/css/image 文件
location ~.*\.(css|js|png|jpg|jpeg)$ { expires 86400s; }
-
注意:
分布式系统里多台机器间文件的last-modified必须保持一致,以免负载均衡到不同机器导致比对失败,**分布式系统尽量关闭掉Etag(每台机器生成的Etag都会不一样)。**但是 if-modified只能精确到秒级(如果每秒进行了多次修改则存在隐患),而 Etag 能每次都能判断。
http { etag off; }
-
只有返回的资源带有
Last-Modified
标识,而浏览器再次请求该资源时才会自动带上If-Modified-Since
请求头。另外If-Modified-Since
只能作用于 GET、HEAD 请求。 -
什么情况下服务器会发送last-modified ?
- 静态资源自动发送。
- 动态资源(例如API接口类)不发送。
-
禁用 last-modified的两种方法:
- 覆盖请求头(置空表示不发送):
add_header Last_modified "";
if_modified_since off;
2、代理缓存
注意,应避免给
XHR
类请求设置代理缓存
-
示意图:
-
原理阐释:
-
缓存目录思想:
创建 1 个缓存总目录,然后利用参数值令 Nginx 自行创建子缓存目录。
-
先打开
proxy_buffering
# 默认已开启,但这里要防止被其他配置关闭(否则不生效也不报错) proxy_buffering on;
-
总体配置思想
proxy_cache_path /usr/local/Nginx_cache levels=2:1 keys_zone=mycache:10m inactive=1d max_size=1g;
proxy_cache mycache;
-
额外配置
- proxy_cache_key:web 缓存的key值,存在如下默认值(3部分加起来就是完整的 url)。
$scheme$proxy_host$request_uri
- proxy_cache_min_uses:资源被访问多少次之后才开启缓存,默认值 1 。
- proxy_cache_valid:可以针对不同的状态码设置不同的缓存时间。
proxy_cache_valid 200 302 10m; proxy_cache_valid 404 1m; # 为 404 页面缓存 1 分钟 proxy_cache_valid any 1m;
- proxy_cache_methods:设置可以缓存的请求方式,默认 Get/Head 。
proxy_cache_methods GET|POST|PUT|DELETE;
-
清除缓存:
-
不缓存与不使用缓存
- 出发点:不是所有的数据都需要 Nginx 服务器都需要缓存,有时候可能会适得其反。
- 两者含义并不一样:
- proxy_no_cache:设置在什么情况下不缓存数据。
- proxy_cache_bypass:设置在什么情况下不使用缓存的数据。
- 两者配置形式一样:或运算,只要在配置条件中满足存在任何一个条件即生效。
- $cookie_xxx:当 Cookie 中包含该 key 时生效。
- $arg_xxx:当请求参数 arg 中包含该 key 时生效。
proxy_no_cache $cookie_nocache $arg_nocache $arg_leaf;
proxy_cache_bypass $cookie_nocache $arg_nocache $arg_leaf;
-
浏览器查看是否击中缓存
- HIT:击中
- MISS:未击中。
五、爬虫过滤
1、初级爬虫过滤
2、高级爬虫过滤
1、拦截特定请求
初级爬虫过滤
-
简介:
-
简单实现:禁止某些爬虫与空 agent 访问。
location / { root /usr/share/Nginx/html; index index.html index.htm index.PHP; if ($http_user_agent ~* "python|java|curl|wget|postman|apipost|httpclient|Apifox|^$"){ return 503; } }
-
curl模拟各种爬虫
curl -A '' test.com curl -I -A 'okhttp' test.com # -I 只返回状态码与响应头,不返回 body
-
禁止搜索引擎爬虫:当我们不想被搜索引擎爬虫干扰时使用,下面参数只列出了部分搜索引擎爬虫。
if ($http_user_agent ~ "FeedDemon|JikeSpider|Indy Library|Alexa Toolbar|AskTbFXTV|AhrefsBot|CrawlDaddy|CoolpadWebkit|Java|Feedly|UniversalFeedParser|ApacheBench|Microsoft URL Control|Swiftbot|ZmEu|oBot|jaunty|Python-urllib|lightDeckReports Bot|YYSpider|DigExt|YisouSpider|HttpClient|MJ12bot|heritrix|EasouSpider|Ezooms|^$" ) { return 503; }
2、限流限速
高级爬虫过滤
-
简介:
-
原理:(传送门)
- 漏桶算法:永远匀速处理请求,超出则抛弃相应请求并返回503。
- 令牌桶算法:当桶里储备有物资时,可处理大量突发请求;当物资被消耗殆尽时,匀速处理请求,除非桶里再次缓存。(相当于漏桶算法的强化版)
-
限制请求速率 ngx_http_limit_req_module
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s; server { location / { limit_req zone=mylimit burst=10 nodelay; } }
-
**注意:**limit_req_zone 只是设置限流参数,如果要生效的话,必须和 limit_req 配合使用。
-
$binary_remote_addr:使用二进制 IP 存储辨别客户端(压缩内存占用量)。
-
zone:myLimit:10m 表示一个大小为10M,名字为 myLimit 的内存区域,1M 能存储16000个 IP 地址的访问信息。
-
rate:rate=1r/s 表示每秒最多处理 1 个请求。实际上 Nginx 以毫秒为粒度追踪请求,所以是每 1000 毫秒 1 个请求。
-
burst:在超过设定的访问速率后缓存的请求数(单独设置还是要等待、依次进行)。
-
nodelay:表示不延迟。设置 no_delay 后,第一个到达的请求和队列中的请求会立即进行处理,不会出现等待的请求。通常与 burst 搭配使用提高突发请求响应。
-
-
限制并发数 ngx_http_limit_conn_module
limit_conn_zone $binary_remote_addr zone=perip:10m; limit_conn_zone $server_name zone=perserver:10m; limit_req_status 510; # 失败时默认返回503,可自定义400-599 server { location / { limit_conn perserver 50; limit_conn perip 5; } }
- 注意:并非所有的连接都被计数,只有在服务器处理了请求并且已经读取了整个请求头时,连接才被计数。
- limit_conn perip 10:key 是 $binary_remote_addr,表示限制单个IP同时最多能持有10个连接。
- limit_conn perserver 100: key 是 $server_name,表示虚拟主机(server) 同时能处理并发连接的总数为100。
-
限制网速 ngx_http_core_module
- limit_rate:限速,默认单位为字节 Byte。
- 案例:20MB 之前不限速,之后限速为 100KB/s 。
limit_rate_after 20m; limit_rate 100k;
-
设置访问白名单:白名单不限流。
limit_req_zone $limit_key zone=mylimit:10m rate=10r/s; geo $limit { default 1; 10.0.0.0/8 0; 192.168.0.0/24 0; 172.20.0.35 0; } map $limit $limit_key { 0 ""; 1 $binary_remote_addr; }
3、爬虫炸弹
-
简介
- 利用 gzip ,将 10GB 文件压缩至 1MB。
- 当非法客户端请求时返回,使其解析并消耗资源。
-
实现过程:
dd if=/dev/zero bs=1M count=10240 | gzip > 10G
location / { # 如果是非法请求 if ($http_user_agent ~* "python|apipost|postman|Apifox|^$"){ rewrite ^(/.*)$ /10G last; } } location =/10G { gzip off; add_header Content-Type 'text/plain'; add_header Cache-Control no-store; add_header content-encoding gzip; }
六、代理
1、正向代理
代理用户,本质为请求转发
实现:
server{
listen 80;
location / {
proxy_pass http://$host$request_uri;
}
}
2、反向代理
upstream + proxy_pass
-
简介:
- 反向代理常作负载均衡,在某些时候两者的含义是模糊的。
-
负载均衡的作用:
- 提高并发处理性能
- 实现故障转移
- 增强可扩展性(灵活)
- 过滤非法请求
-
3种常见负载均衡策略
-
【简单配置】
- upstream(上游):定义一组可使用的服务器。
- server:此处的 server 即 upstream 下的服务器地址、端口配置。
# 定义 upstream ,命名为 backend upstream backend{ server 127.0.0.1:8081 weight=1; server 127.0.0.1:8082 weight=2; server 127.0.0.1:8083 weight=10; } location / { proxy_pass http://backend; default_type text/plain; }
server{ listen 8081; # listen 8082; # listen 8083; server_name localhost; default_type text/plain; }
-
【进阶配置】
反向代理叙述:所有带有 proxy 开头的指令全部都是反向代理配置。
-
在作反向代理时,
location
路径末尾加或不加斜线/d
的区别:location /test/ { proxy_pass http://127.0.0.1/; # proxy_pass http://127.0.0.1; }
假设想请求 abc.html,真实访问路径如下:
-
加:
http://127.0.0.1/abc.html
-
不加:
http://127.0.0.1/test/abc.html
总结:如果我不加的话,他就会替我加!(包括location路径中的一切)
-
-
负载均衡状态
用于标注服务器状况
状态 概述 down 当前的 server 暂不参与负载均衡 backup 预留的备份服务器 max_fails 允许请求失败的次数 fail_timeout 失败之后 server 暂停接受请求的时间 max_conns 限制的最大接收连接数(默认 0 ,即不受限制) -
backup:原可用的所有服务都不可用时才会生效。
-
max_fails + fail_timeout:两者通常结合使用。
-
范例:当该服务器在 10s 内出现 3 次失败后,暂时该服务器在下一个时间段 10s 内的使用( fail_timeout 描述的是时间段)。
server 127.0.0.1:8081 max_fails=3 fail_timeout=10s;
proxy_next_upstream error timeout invalid_header http_500 http_503 http_404;
-
-
负载均衡策略
算法名称 说明 轮询 默认 weigth 权重,默认 1 ip_hash 依据ip分配 url_hash 依据URL分配 cookie_hash 依据 Cookie 内的某些字段分配,如 session least_conn 最少连接优先选择 fair 依据响应时间(第三方模块) upstream backend{ ip_hash; least_conn; hash $request_uri; # 基于 Java 中的 Java Session Id hash $cookie_JSESSIONID server 127.0.0.1:8081 weigth=1; server 127.0.0.1:8082; server 127.0.0.1:8083; }
3、反向代理实战
-
对特定资源实现负载均衡
upstream imagebackend{ server 127.0.0.1:8081; server 127.0.0.1:8082; } upstream videobackend{ server 127.0.0.1:8083; server 127.0.0.1:8084; } server{ listen 80; server_name localhost; # image locatio /image/ { proxy_pass http://imagebackend; } # video locatio /video/ { proxy_pass http://videobackend; } }
-
对不同域名实现负载均衡
upstream aaa{ server 127.0.0.1:8081; server 127.0.0.1:8082; } upstream bbb{ server 127.0.0.1:8083; server 127.0.0.1:8084; } server{ listen 80; server_name one.com; locatio / { proxy_pass http://aaa; } } server{ listen 80; server_name two.com; locatio / { proxy_pass http://bbb; } }
七、Lua
lua 是一门简洁、轻量、可扩展的脚本语言,其采用 C 语言编写。
1、入门
-
简介:Lua的设计目的是为了嵌入到其他应用程序,从而为其他应用程序提供灵活的扩展和定制功能。
-
安装:绝大部分 Linux 系统已默认安装 Lua 。
yum install -y lua
-
2种执行模式:
-
交互式
lua
-
脚本式
- 带 lua
# 编辑、执行 vim lua_01 lua lua_01
vim lua_01
#! /usr/bin/lua print("Hello Lua")
chmod 777 lua_01 ./lua_01
-
语法细则:分号
;
加不加都行 -
注释
- 单行注释
--注释内容
- 多行注释
--[[ 注释内容 --]]
- 取消多行注释:相当于两个单行注释
---[[ 注释失效 --]]
-
变量定义:
- 命名规则与其他语言规则类似,例如 Java。
- 弱定义、弱类型 -> 无需提前定义直接使用,类型也不用声明。
-
nil
表示未赋值(nil /nɪl/:零、空)。 - 全局变量:默认即全局变量
- 局部变量:需加关键字 local 声明,否则会被当成全局变量。
- 注意:Lua内部全局变量的命名规则为 -> 以下划线开头连接大写字母的变量名。所以一般约定我们不这么定义变量,以免和 Lua 冲突。
> a=10 > print(a) 10
> local b=20 > print(b) nil
> local c=30; print(c) 30
-
关键字
-
部分运算规则:
10^2 --> 100 10==10 --> true 10~=10 --> false and or not --> 逻辑非 .. --> 字符串连接,例:"aa".."bb",输出 aabb # --> 返回字符串长度,例:#"hello",输出 5
-
8种数据类型
nil # 空、无效值 boolean number # 数值,包含 integer 整数、float 双精度(这与其他语言不同) string function # 函数 table # 表 thread # 线程 userdata # 用户数据
- 可以使用
type()
来检测数据类型
> print(type(123)) number
注意:
-
只要将变量名赋值为 nil,那么垃圾回收就会释放该变量所占用的内存。
-
在boolean中,lua 只会将 false 与 nil 视为假,其余均为真!
-
不管是 integer 或者 float ,
type()
返回的均为 number。
字符串声明:
- 单行声明:单引号或者双引号。
- 多行声明:
[[ sample ]]
> a="123" > b="456" > c=[[ >> 7 >> 8 >> 9 >> ]]
- 可以使用
-
table数据类型:lua 中最主要和最为强大的数据结构,可以以一种简单的方式表达数组、集合、记录等内容。**注意:**数组下标从 1 开始。
> a={} > b={"A","B","C"} > print(b[1]) A
> arr["A"]=10 > arr["B"]=20 > arr[1] -- 当为以上的方式书写时,不能用序号获取 nil > arr["A"] 10
> arr = {"A",X=10,Y=20} > arr[1] A > arr[2] -- 注意此时的序号关系 B > arr.X -- 注意这种书写方式 10
-
- 格式
function 函数名(参数) -- 具体内容 end
- 范例
> function add(n,m) >> print(n+m) >> end > add(1,2) 3
> function add(...) >> a,b,c=... >> return a,c >> end > q,w,e=add(1,2,3) > print(q,e) 1 2 3
-
if语句:end作终结符
if then elseif then else -- precedure end
- 范例
> function testif(age) >> if age <= 18 then >> return "未成年" >> elseif age <= 45 then >> return "中年人" >> else >> return "老年人" >> end >> end > print(testif(20)) 中年人
-
while与repeat:end、until 作终结符,不支持 a++ 类语法。
> function testwhile() >> i=10 >> while i<20 do >> print(i) >> i=i+1 >> end >> end
> function testrepeat() >> i=10 >> repeat >> print(i) >> i=i-1 >> until i<1 >> end
2、openResty
openResty = Nginx + lua