Nginx介绍背景介绍Nginx是一个高性能的HTTP和反向代理的Web服务,同时也是一个POP3/SMTP/IMAP代理服务器,由伊戈尔·塞索耶夫(俄罗斯人)用C语言开发Nginx优点 速度更快,并发更高 配置简单,拓展性强 高可靠 热部署 成本低、BSD许可证 Nginx功能特性Nginx的功能特性大体上可分为基本HTTP服务、高级HTTP服务、邮件服务基本HTTP服务 处理静态文件 反向代理 负载均衡 文件压缩 SSL协议 高级HTTP服务 设置虚拟主机 支持网络监控 支持FLV和MP4流媒体传输 邮件服务 支持内部IMAP/POP3代替服务 支持内部SMTP服务 环境安装源代码安装(推荐)1.下载Nginx可在官网下载Lunx/Windows的Nginx,http://nginx.org/下载好后解压nginxsh tar -xzf 文件包1.2下载OpenRestryOpenRestry自带对应的Nginx,并且内部支持使用Lua脚本可在官网下载OpenRestry,http://openresty.org/cn/download.html下载好后解压OpenRestrysh tar -xzf 文件包2.确认环境由于Nginx是基于c语言开发,因此我们需要确认是否由c语言环境sh yun install -y gcc gcc --version由于Nginx需要用上正则表达式来操作Rewirte,因此需要安装PCREsh yum install -y pcre pcre-devel rpm -qa pcre pcre-devel由于Nginx使用了一些压缩算法,因此需要安装zlibsh yum install -y zlib zlib-devel rpm -qa zlib zlib-devel可以一键安装,若已安装会更新为最新版sh yum install -y gcc pcre pcre-devel zlib zlib-devel openssl openssl-devel3.安装先执行configuresh ./configure若需要特殊配置,可添加指令```sh ./configure --prefix=/usr/local/nginx \ --sbin-path=/usr/local/nginx/sbin/nginx \ --modules-path=/usr/local/nginx/modules \ --conf-path=/usr/local/nginx/conf/nginx.conf \ --error-log-path=/usr/local/nginx/logs/error.log \ --http-log-path=/usr/local/nginx/logs/access.log \ --pid-path=/usr/local/nginx/logs/nginx.pid \ --lock-path=/usr/local/nginx/logs/nginx.lock```详细的配置可自行百度,或者sh configure --help最后安装sh make && make install Nginx默认安装/usr/local/nginx OpenRestry默认安装/usr/local/openrestry/nginx yum安装sh yum -y install nginx查看是否安装成功sh whereis nginx启动nginx,进入sbin里打开nginxsh cd ../user/sbin ./nginx /etc/nginx/nginx.conf //yum方式安装后默认配置文件的路径 /usr/share/nginx/html //nginx网站默认存放目录 /usr/share/nginx/html/index.html //网站默认主页路径 目录结构在nginx里,有几个重要的文件 html:存放静态资源 conf:存放配置文件 nginx.conf:nginx的配置 log:存放日志文件 error.log:错误日志 access.log:访问日志 Nginx控制命令行控制命令行控制需要在./sbin目录下执行| 命令 | 效果 | | ------------------- | --------------------------------------- | | ./nginx | 开启nginx | | ./nginx -t | 测试配置文件语法是否正确 | | ./nginx -T | 测试配置文件语法是否正确,并输出配置信息 | | ./nginx -s stop | 立刻关闭整个服务 | | ./nginx -s quite | 关闭整个服务 | | ./nginx -s reopen | 重新打开日志 | | ./nginx -s reload | 重新读取配置 | | ./nginx -p:prefix | 指定nginx目录,默认/user/local/nginx/ | | ./nginx -c:filename | 指定nginx配置,默认conf/nginx.conf | | ./nginx -g | 补充配置 |信号量控制信号量就是操控进程,可以通过直接操控进程来操控nginx通常情况下,一个nginx含有一个master进程和多个worker进程作为管理员,我们只需要控制master进程就可以控制整个nginx在控制nginx前,我们需要获取nginx对应的进程pid方法一:sh ps -ef | grep nginx方法二:在log目录下有一个nginx.pid文件,打开此文件可获取对应master的pidsh cd ./user/local/nginx/log ./nginx.pid要想使用信号,格式为:sh kill -信号 PID| 信号 | 作用 | | -------- | ---------------- | | TERM/INT | 立即关闭整个服务 | | QUIT | 关闭整个服务 | | HUP | 重新读取配置 | | USER1 | 重新打开日志 | | USER2 | 更新nginx | | WINCH | 关闭worker进程 |Nginx配置nginx.conf配置文件有三大块:全局快、events块、http块全局块tex 指令名 指令值; #全局块，主要设置Nginx服务器整体运行的配置指令| 指令名 | 指令值 | 默认值 | 作用 | | ----------------- | ------- | ------------- | -------------------------------------------- | | user | 用户 | nobody | 指定访问文件夹(静态文件)的用户,若无权限则403 | | master_processes | on/off | on | 指定是否开启工作进程 | | *worker_processes | 数值 | 1 | 配置nginx并发数,建议与cpu内核数一致或更低 | | daemon | on/off | on | 是否后台执行nginx | | pid | 路径 | .../nginx.pid | 存储pid的文件路径 | | error_log | 路径 | .../error.log | 存储错误日志路径 | | include | xx.conf | 无 | 引入其他配置 |events块```texevents块,主要设置,Nginx服务器与用户的网络连接,这一部分对Nginx服务器的性能影响较大events {指令名 指令值; } ```| 指令 | 指令值 | 默认值 | 作用 | | ------------------- | ------------------------ | ---------------- | ----------------------------------------------- | | accept_mutex | on/off | on | 网络连接序列化 | | multi_accept | on/off | off | 是否运行同时收到多个网络连接,建议设置on | | worker_connections | 数值 | 512 | 单个worker最大连接数 | | *use | select/poll/epoll/kqueue | 根据操作系统而定 | nginx底层使用的函数.在linux2.6以上默认使用epoll |http块```texhttp块，是Nginx服务器配置中的重要部分，代理、缓存、日志记录、第三方模块配置...http {指令名 指令值; #server块，是Nginx配置和虚拟主机相关的内容 server { #location块，基于Nginx服务器接收请求字符串与location后面的 值进行匹配，对特定请求进行处理 指令名 指令值; location uri { 指令名 指令值; ... } ... } ... } ```| 指令 | 指令值 | 默认值 | 作用块 | 作用 | | ------------------------------ | ------------------------------------------------------------ | -------------------------------------- | :------------------: | ------------------------------------------------------------ | | include | 导入外部配置 | 无 | http | 通常会在http块中导入mime.type,这是用来解析前端响应的资源,使用default必须导入mime.type | | default_type | 资源类型如:application/json、application/octet-stream(二级制文件) | text/plain | http/server/location | 设置响应的资源类型 | | access_log | log路径 格式名(不填则默认) | logs/access.log combined | http/server/location | 设置log输出路径 | | log_format | 格式名 格式 | combined "..." | http | 格式化log输出样式 | | sendfile | on/off | off | http/server/location | 是否使用sendfile()函数提升文件传输性能,建议设置为on | | tcp_nopus | on/off | off | http/server/location | sendfile打开的状态下才会生效,提高网络传输效率,建议设置为on | | tcp_nodelay | on/off | off | http/server/location | 有网的的情况下才生效,保证网络连接实效性,建议设置为on | | keepalive_timeout | 数值 | 75s | http/server/location | http长连接超时时间 | | keepalive_requests | 数值 | 100 | http/server/location | 一个长连接最多被使用次数 | | listen | 数值 | 80 | server | 监听端口 | | server_name | ip/域名 | localhost | server | 监听的IP/域名 | | root | 资源目录 | 无 | location | 静态资源所对应的目录 | | alias | 资源目录 | 无 | location | 同root | | index | 静态资源 | 无 | location | 访问uri默认打开的静态资源 | | error_page | 状态码 uri | 无 | server | 当出现该状态码时,响应某location的uri | | gizp | on/off | off | http/server/location | 打开压缩模块,建议设置为on | | gzip_types | 资源类型如:application/json | text/html | http/server/location | 指定压缩文件类型 | | gzip_comp_level | 1-9 | 1 | http/server/location | 压缩强度,1最低,9最高,建议设置为5或6 | | gzip_vary | on/off | off | http/server/location | 被压缩文件是否带“Vary:Accept-Encoding”的响应头,建议设置为on | | gzip_buffers | 空间数 大小 | 32 4k | http/server/location | 压缩申请的空间数和大小 | | gzip_disable | 正则表达式 | 无 | http/server/location | "User-Agent"请求头匹配正则表达式,则不压缩,建议设置为"MSIE [1-6].",对IE6以下浏览器禁用压缩 | | gzip_http_version | 1.0/1.1 | 1.1 | http/server/location | 针对不同HTTP协议版本选择性地开启Gzip功能 | | gzip_min_length | 数据大小 | 20 | http/server/location | 超过指定数据大小则不压缩,建议设置为1k | | gzip_proxied | off/any/请求头信息 | off | http/server/location | 建议设置为expired no-cache no-store private auth | | gzip_static | on/off | off | http/server/location | 避免gzip和sendfile,建设置为on | | add_header | 响应头信息 | 无 | http/server/location | 设置响应头信息 | | expires | time/off/max | off | http/server/location | 设置缓存时间(add_header也可以设置) | | valid_referers | none/blocked/server_names/正则表达式 | 无 | server/location | 设置防盗链 | | proxy_pass | url | 无 | location | 设置被代理服务器地址 | | proxy_set_header | 请求头 信息 | 无 | location | 代理时,更改/添加请求头信息 | | proxy_redirect | 被代理IP 代理IP/default/off | default | location | 代理时,更改请求头Refer和响应头Location为代理IP | | ssl | off | on/off | http、server | 启HTTPS,可以使用 listen 443 ssl | | ssl_certificate | 路径 | 无 | http、server | PEM格式证书 | | ssl_certificate_key | 路径 | 无 | http、server | 证书Key | | ssl_session_cache | off/none/builtin/shared | none | http、server | SSL会话缓存 | | ssl_session_timeout | 时间 | 5m | http、server | 缓存中的会话参数时间 | | ssl_ciphers | 密码格式 | HIGH:!aNULL:!MD5 | http、server | 指出允许的密码 | | ssl_prefer_server_ciphers | on/off | off | http、server | 指定是否服务器密码优先客户端密码 | | proxy_cache_path | 路径 属性 | 无 | http | 设置Nginx本地缓存路径 | | proxy_cache | name/off | off | http/server/location | 指定Nginx本地缓存名字 | | proxy_cache_key | 值 | $scheme$proxy_host$request_uri | http/server/location | 设置Nginx缓存文件名使用的是什么值的MD5 | | proxy_cache_valid | 状态码 时间 | 无 | http/server/location | 设置Nginx缓存状态码和状态码缓存时间 | | proxy_cache_min_uses | 数值 | 1 | http/server/location | 设置资源被访问多少次后被缓存 | | proxy_cache_methods | 请求方法 | GET | http/server/location | 设置缓存哪些HTTP方法 | | proxy_cache_purge | name key | 无 | http/server/location | 清除缓存 | | proxy_no_cache | 条件 | 无 | http/server/location | 符合条件不缓存 | | proxy_cache_bypass | 条件 | 无 | http/server/location | 符合条件不从缓存中获取数据 | | proxy_buffers | 数量 文件大小 | 256 8k | http/server/location | 响应体初始大小,当不够时会再申请,建议调小 | | proxy_buffer_size | 文件大小 | 4k/8k | http/server/location | 响应头初始大小,当不够时会再申请,建议调小 | | proxy_busy_buffer_size | 文件大小 | 无 | http/server/location | nginx会在没有完全读完后端响应就开始向客户端传送数据，所以它会划出一部分busy状态的buffer来专门向客户端传送数据 | | autoindex off | on/off | off | http/server/location | 启用或禁用目录列表输出 | | autoindex_exact_size | on/off | on | http/server/location | 显示目录文件的具体大小 | | autoindex_format | html/json/xml | html | http/server/location | 目录显示格式 | | autoindex_localtime | on/off | off | http/server/location | 显示当前时间 | | auth_basic | on/off | off | http/server/location | 开启用户认证 | | auth_basic_user_file | 路径 | 无 | http/server/location | 指定用户名和密码所在文件 | | charset | 编码 | 无 | http/server/location | 指定编码,建议设置utf-8 | | lua_package_path | 路径 | "user/local/openrestry/lualib/?.lua;;" | http | 导入第三方lua模块 | | lua_package_cpath | 路径 | "user/local/openrestry/lualib/?.so;;" | http | 导入c模块 | | server_names_hash_bucket_size | 数据大小 | | http | 服务器名大小限制 | | client_header_buffer_size | 数据大小 | | http | 请求头大小限制 | | large_client_header_buffers | 个数 数据大小 | | http | 请求行+请求头限制个数大小 | | client_max_body_size | 数据大小 | | http | 最大上传文件 | | limit_conn_zone | 参数 zone=名字:带宽 | 无 | http | 限制参数的并发连接数以及带宽,名字可随便取,不重复就行 |servername详解servername是用来用户访问的ip,若用户ip符合servername,则走该servername的逻辑*注意:若用户ip不符合servername,比如用户通过外网ip访问,但是nginx只监听了127.0.0.1,则默认走带default_server,default_server默认是第一个server``` server{ listen 8080; server_name 127.0.0.1; location /{ root html; index index.html; } } server{ listen 8080 default_server; server_name localhost; default_type text/plain; return 444 'This is a error request'; }若用户以外网ip访问,则走第二个server```其中,servername有三种匹配方式 精确匹配(ip/域名) 通配符匹配(.baidu.com/www.baidu.) 正则表达式 若三种方式同时匹配一个ip,顺序是:``` No1:准确匹配server_name(www.baidu.com)No2:通配符在开始时匹配server_name成功(*.baidu.com)No3:通配符在结束时匹配server_name成功(www.baidu.*)No4:正则表达式匹配server_name成功No5:被默认的default_server处理，如果没有指定默认找第一个server ```location详解location有四种匹配方式 不带符号 uri(/abc) =uri(=/abc) ~正则表达式(~^/abc\w$) ^~uri(^~ /abc) @变量(error_page 404 @a;location @a{...}) 其中^~uri优先级最高root详解root访问资源路径,其访问原理为:``` location /images { root /usr/local/nginx/html; }root的处理结果是: root路径+location路径若用户以ip/images/mv.png则打开/usr/local/nginx/html/images/mv.png```因此root有个缺陷,就是访问资源路径时,必须将资源放在指定的uri文件夹(images) 而alias可以解决此问题alias访问资源路径,其访问原理为:``` location /images { alias /usr/local/nginx/html; }root的处理结果是: alias路径若用户以ip/images/mv.png则打开/usr/local/nginx/html/mv.png```index详解若用户uri不指定任何文件,则访问Index文件``` location /images { root /usr/local/nginx/html; index demo.html }若用户以ip/images则打开/usr/local/nginx/html/demo.html若用户以ip/images/mv.png则打开/usr/local/nginx/html/images/mv.png```error_page详解error_page有三种匹配方法: error_page 状态码 url :直接跳转 server { error_page 404 http://www.itcast.cn; } error_page 状态码 /xx.html:重定向 server{ error_page 500 502 503 504 /50x.html; location =/50x.html{ root html; } } error_page 状态码 @变量:通过@跳转 server{ error_page 500 502 503 504 @jump_to_error; location @jump_to_error { index 50x.html; } }另外,error_page可以修改状态码,如用户访问404时,以200形式返回给用户server{ error_page 404 =200 /50x.html; location =/50x.html{ root html; } }gzip_proxied详解反向代理时,根据请求头"Content-Length"信息来开启压缩 off - 关闭Nginx服务器对后台服务器返回结果的Gzip压缩 expired - 启用压缩，如果header头中包含 "Expires" 头信息 no-cache - 启用压缩，如果header头中包含 "Cache-Control:no-cache" 头信息 no-store - 启用压缩，如果header头中包含 "Cache-Control:no-store" 头信息 private - 启用压缩，如果header头中包含 "Cache-Control:private" 头信息 no_last_modified - 启用压缩,如果header头中不包含 "Last-Modified" 头信息 no_etag - 启用压缩 ,如果header头中不包含 "ETag" 头信息 auth - 启用压缩 , 如果header头中包含 "Authorization" 头信息 any - 无条件启用压缩 gzip_static详解由于gzip_static使用的是http_gzip_static_module,而nginx默认安装时不导入此模块,因此需要在安装时指定导入此模块(1)查询当前Nginx的配置参数nginx -V(2)将nginx安装目录下sbin目录中的nginx二进制文件进行更名cd /usr/local/nginx/sbin mv nginx nginxold(3) 进入Nginx的安装目录cd /root/nginx/core/nginx-1.16.1(4)执行make clean清空之前编译的内容make clean(5)使用configure来配置参数./configure --with-http_gzip_static_module(6)使用make命令进行编译make(7) 将objs目录下的nginx二进制执行文件移动到nginx安装目录下的sbin目录中mv objs/nginx /usr/local/nginx/sbin(8)执行更新命令make upgrade浏览器缓存| header | 说明 | | ------------- | ------------------------------------------- | | Expires | 缓存过期的日期和时间 | | Cache-Control | 设置和缓存相关的配置信息 | | Last-Modified | 请求资源最后修改时间 | | ETag | 请求变量的实体标签的当前值，比如文件的MD5值 |浏览器缓存过期,会先向Nginx服务器获取响应头,然后判断如何获取响应体在获取资源时,有时候资源没有大小,就是走了强缓存;有时候资源只有几百B(只获取了响应头),就是走了弱缓存可以通过配置Nginx的expires或add_header来调整浏览器的缓存方式,下表为add_header的可使用信息| must-revalidate | 可缓存但必须再向源服务器进行确认 | | ---------------- | ---------------------------------------------- | | no-cache | 缓存前必须确认其有效性 | | no-store | 不缓存请求或响应的任何内容 | | no-transform | 代理不可更改媒体类型 | | public | 可向任意方提供响应的缓存 | | private | 仅向特定用户返回响应 | | proxy-revalidate | 要求中间缓存服务器对缓存的响应有效性再进行确认 | | max-age=<秒> | 响应最大Age值 | | s-maxage=<秒> | 公共缓存服务器响应的最大Age值 |跨域问题跨域问题解决方法有很多,其主要原理就是通过添加对应请求头,我们可以在服务端响应数据时添加(如java的@CrossOrigin),也可以在Nginx处添加location /getUser{ add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE; default_type application/json; return 200 '{"id":1,"name":"TOM","age":18}'; }防盗链当网站发生Http请求时,会携带一个Referer请求头,里面包含网站的Ip.Nginx可以通过检测Referer信息来判断是否运行请求获取资源 none: 如果Header中的Referer为空，允许访问 blocked:在Header中的Referer不为空，但是该值被防火墙或代理进行伪装过，如不带"http://" 、"https://"等协议头的资源允许访问 server_names:指定具体的域名或者IP string: 可以支持正则表达式和*的字符串。如果是正则表达式，需要以~开头表示，例如 ``` location ~*.(png|jpg|gif){ valid_referers none blocked www.baidu.com; if ($invalid_referer){ return 403; } root /usr/local/nginx/html;} ```遇到的问题：Referer的限制比较粗，比如随意加一个Referer，上面的方式是无法进行限制的。那么这个问题改如何解决？此处我们需要用到Nginx的第三方模块ngx_http_accesskey_module本地缓存Nginx本地缓存有两种方法,一种是proxy_cache,另一种使用luaproxy_cacheproxy_cache_pathproxy_cache主要是将服务器数据缓存已文件形式保存到本地,若不设置proxy_cache_path则默认缓存至内存而proxy_cache_path属性配置如下:levels: 指定该缓存空间对应的目录，最多可以设置3层，每层取值为1|2如 :levels=1:2 缓存空间有两层目录，第一次是1个字母，第二次是2个字母 举例说明: itheima[key]通过MD5加密以后的值为 43c8233266edce38c2c9af0694e2107d levels=1:2 最终的存储路径为/usr/local/proxy_cache/d/07 levels=2:1:2 最终的存储路径为/usr/local/proxy_cache/7d/0/21 levels=2:2:2 最终的存储路径为??/usr/local/proxy_cache/7d/10/e2keys_zone:用来为这个缓存区设置名称和指定大小，如：keys_zone=itcast:200m 缓存区的名称是itcast,大小为200M,1M大概能存储8000个keysinactive:指定缓存的数据多次时间未被访问就将被删除，如：inactive=1d 缓存数据在1天内没有被访问就会被删除max_size:设置最大缓存空间，如果缓存空间存满，默认会覆盖缓存时间最长的资源，如:max_size=20g配置实例:http{ proxy_cache_path /usr/local/proxy_cache keys_zone=itcast:200m levels=1:2:1 inactive=1d max_size=20g; }缓存清除缓存清除可以手动去rm -rf /usr/local/proxy_cache/......删除,或者使用第三方模块ngx_cache_purge（1）下载ngx_cache_purge模块对应的资源包，并上传到服务器上。ngx_cache_purge-2.3.tar.gz（2）对资源文件进行解压缩tar -zxf ngx_cache_purge-2.3.tar.gz（3）修改文件夹名称，方便后期配置mv ngx_cache_purge-2.3 purge（4）查询Nginx的配置参数nginx -V（5）进入Nginx的安装目录，使用./configure进行参数配置./configure --add-module=/root/nginx/module/purge（6）使用make进行编译make（7）将nginx安装目录的nginx二级制可执行文件备份mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginxold（8）将编译后的objs中的nginx拷贝到nginx的sbin目录下cp objs/nginx /usr/local/nginx/sbin（9）使用make进行升级make upgrade（10）在nginx配置文件中进行如下配置server{ location ~/purge(/.*) { proxy_cache_purge itcast itheima; } }proxy_no_cacheproxy_no_cache $cookie_nocache $arg_nocache $arg_comment;proxy_cache_bypassproxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment;lua缓存下载模块使用下载模块后,页面将会显示对应的目录的文件,用户点击后即可下载``` location /download{ root /usr/local; autoindex on; autoindex_exact_size on; autoindex_format html; autoindex_localtime on; }```用户认证实现步骤:1.nginx.conf添加如下内容location /{ root /html; index index.html; auth_basic 'please input your auth'; auth_basic_user_file htpasswd; }2.我们需要使用htpasswd工具生成yum install -y httpd-toolshtpasswd -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配置文件，都需要先进入到nginx的安装目录的sbin目录，然后使用nginx的二级制可执行文件来操作，相对来说操作比较繁琐,可以通过设置为系统服务来优化,另外也可以通过系统服务来设置开机自启环境变量(1)修改/etc/profile文件sh vim /etc/profile 在最后一行添加 export PATH=$PATH:/usr/local/nginx/sbin(2)使之立即生效sh source /etc/profile(3)执行nginx命令sh nginx -V开机自启(1) 在/usr/lib/systemd/system目录下添加nginx.service,内容如下:sh vim /usr/lib/systemd/system/nginx.service```tex [Unit] Description=nginx web service Documentation=http://nginx.org/en/docs/ After=network.target[Service] Type=forking PIDFile=/usr/local/nginx/logs/nginx.pid ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf ExecStart=/usr/local/nginx/sbin/nginx ExecReload=/usr/local/nginx/sbin/nginx -s reload ExecStop=/usr/local/nginx/sbin/nginx -s stop PrivateTmp=true[Install] WantedBy=default.target ```(2)添加完成后如果权限有问题需要进行权限设置chmod 755 /usr/lib/systemd/system/nginx.service(3)使用系统命令来操作Nginx服务启动: systemctl start nginx 停止: systemctl stop nginx 重启: systemctl restart nginx 重新加载配置文件: systemctl reload nginx 查看nginx状态: systemctl status nginx 开机启动: systemctl enable nginxRewriteRewrite是Nginx的编程语法,主要实现URL的重写Set该指令用来设置一个新的变量。| 语法 | set $variable value; | | ------ | -------------------- | | 默认值 | — | | 位置 | server、location、if |variable:变量的名称，该变量名称要用"$"作为变量的第一个字符，且不能与Nginx服务器预设的全局变量同名。value:变量的值，可以是字符串、其他变量或者变量的组合等。Rewrite常用全局变量| 变量 | 说明 | | ------------------ | ------------------------------------------------------------ | | $args | 请求URL中的请求指令。比如http://192.168.200.133:8080?arg1=value1&args2=value2中的"arg1=value1&arg2=value2"，功能和$query_string一样 | | $http_user_agent | 用户访问服务的代理信息(如果通过浏览器访问，记录的是浏览器的相关版本信息) | | $host | 访问服务器的server_name值 | | $document_uri | 当前访问地址的URI。比如http://192.168.200.133/server?id=10&name=zhangsan中的"/server"，功能和$uri一样 | | $document_root | 当前请求对应location的root值，如果未设置，默认指向Nginx自带html目录所在位置 | | $content_length | 请求头中的Content-Length的值 | | $content_type | 请求头中的Content-Type的值 | | $http_cookie | 客户端的cookie信息，可以通过add_header Set-Cookie 'cookieName=cookieValue'来添加cookie数据 | | $limit_rate | Nginx服务器对网络连接速率的限制，也就是Nginx配置中对limit_rate指令设置的值，默认是0，不限制。 | | $remote_addr | 客户端的IP地址 | | $remote_port | 客户端与服务端建立连接的端口号 | | $remote_user | 客户端的用户名，需要有认证模块才能获取 | | $scheme | 访问协议 | | $server_addr | 服务端的地址 | | $server_name | 客户端请求到达的服务器的名称 | | $server_port | 客户端请求到达服务器的端口号 | | $server_protocol | 客户端请求协议的版本，比如"HTTP/1.1" | | $request_body_file | 发给后端服务器的本地文件资源的名称 | | $request_method | 客户端的请求方式，比如"GET","POST"等 | | $request_filename | 当前请求的资源文件的路径名 | | $request_uri | 当前请求的URI，并且携带请求参数，比如http://192.168.200.133/server?id=10&name=zhangsan中的"/server?id=10&name=zhangsan" | | $request | request的所有信息 | | $status | 响应的状态码 | | $invalid_referer | Referer请求头与防盗链是否匹配(布尔) |if指令该指令用来支持条件判断，并根据条件判断结果选择不同的Nginx配置。| 语法 | if (condition){...} | | ------ | ------------------- | | 默认值 | — | | 位置 | server、location |condition为判定条件，可以支持以下写法： 变量名。如果变量名对应的值为空或者是0，if都判断为false,其他条件为true。 ``` if ($param){} 2. 使用"="和"!="比较变量和字符串是否相等，满足条件为true，不满足为false if ($request_method = POST){ return 405; } ```注意：此处和Java不太一样的地方是字符串不需要添加引号。 使用正则表达式对变量进行匹配，匹配成功返回true，否则返回false。变量与正则表达式之间使用"~","~","!~","!~"来连接。 "~"代表匹配正则表达式过程中区分大小写，"~*"代表匹配正则表达式过程中不区分大小写"!~"和"!~*"刚好和上面取相反值，如果匹配上返回false,匹配不上返回trueif ($http_user_agent ~ MSIE){ #$http_user_agent的值中是否包含MSIE字符串，如果包含返回true }注意：正则表达式字符串一般不需要加引号，但是如果字符串中包含"}"或者是";"等字符时，就需要把引号加上。 判断请求的文件是否存在使用"-f"和"!-f", 当使用"-f"时，如果请求的文件存在返回true，不存在返回false。当使用"!f"时，如果请求文件不存在，但该文件所在目录存在返回true,文件和目录都不存在返回false,如果文件存在返回falseif (-f $request_filename){ #判断请求的文件是否存在 } if (!-f $request_filename){ #判断请求的文件是否不存在 } 判断请求的目录是否存在使用"-d"和"!-d", 当使用"-d"时，如果请求的目录存在，if返回true，如果目录不存在则返回false当使用"!-d"时，如果请求的目录不存在但该目录的上级目录存在则返回true，该目录和它上级目录都不存在则返回false,如果请求目录存在也返回false. 判断请求的目录或者文件是否存在使用"-e"和"!-e" 当使用"-e",如果请求的目录或者文件存在时，if返回true,否则返回false.当使用"!-e",如果请求的文件和文件所在路径上的目录都不存在返回true,否则返回false 判断请求的文件是否可执行使用"-x"和"!-x" 当使用"-x",如果请求的文件可执行，if返回true,否则返回false当使用"!-x",如果请求文件不可执行，返回true,否则返回falsebreak指令该指令用于中断当前相同作用域中的其他Nginx配置。与该指令处于同一作用域的Nginx配置中，位于它前面的指令配置生效，位于后面的指令配置无效。| 语法 | break; | | ------ | -------------------- | | 默认值 | — | | 位置 | server、location、if |使用break后,会自动覆盖原有的return,并添加对应的root和index,若index没有设置,则默认打开当前目录下的index.htmlreturn指令该指令用于完成对请求的处理，直接向客户端返回响应状态代码。在return后的所有Nginx配置都是无效的。| 语法 | return code [text];return code URL;return URL; | | ------ | -------------------------------------------------------- | | 默认值 | — | | 位置 | server、location、if |code:为返回给客户端的HTTP状态代理。可以返回的状态代码为0~999的任意HTTP状态代理text:为返回给客户端的响应体内容，支持变量的使用URL:为返回给客户端的URL地址rewrite指令该指令通过正则表达式的使用来改变URI。可以同时存在一个或者多个指令，按照顺序依次对URL进行匹配和处理。| 语法 | rewrite regex replacement [flag]; | | ------ | --------------------------------- | | 默认值 | — | | 位置 | server、location、if |regex:用来匹配URI的正则表达式replacement:匹配成功后，用于替换URI中被截取内容的字符串。如果该字符串是以"http://"或者"https://"开头的，则不会继续向下对URI进行其他处理，而是直接重定向给客户端。flag:用来设置rewrite对URI的处理行为，可选值有如下： last:默认值.匹配成功后重写走server块执行 break:匹配成功后直接在当前location块执行 redirect:rewrite后临时重定向 permanent:rewrite后永久重定向 rewrite_log指令该指令配置是否开启URL重写日志的输出功能。| 语法 | rewrite_log on\|off; | | ------ | -------------------------- | | 默认值 | rewrite_log off; | | 位置 | http、server、location、if |开启后，URL重写的相关日志将以notice级别输出到error_log指令配置的日志文件汇总。SSL开启ssl网站就可以通过https进行访问nginx添加SSL的支持》将原有/usr/local/nginx/sbin/nginx进行备份 》拷贝nginx之前的配置信息 》在nginx的安装源码进行配置指定对应模块 ./configure --with-http_ssl_module 》通过make模板进行编译 》将objs下面的nginx移动到/usr/local/nginx/sbin下 》在源码目录下执行 make upgrade进行升级，这个可以实现不停机添加新模块的功能SSL固定格式nginx关于ssl配置有很多,但是其有固定格式nginx listen 443 ssl http2; ssl_certificate PEM路径; ssl_certificate_key PEMkEY路径; ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; add_header Strict-Transport-Security "max-age=31536000"; error_page 497 https://$host$request_uri;负载均衡负载均衡方式 用户手动选择 DNS轮询 四/七层负载均衡 四/七层负载均衡是目前最主流的负载均衡方式所谓四层负载均衡指的是OSI七层模型中的传输层，主要是基于IP+PORT的负载均衡实现四层负载均衡的方式： 硬件：F5 BIG-IP、Radware等 软件：LVS、Nginx、Hayproxy等所谓的七层负载均衡指的是在应用层，主要是基于虚拟的URL或主机IP的负载均衡实现七层负载均衡的方式： 软件：Nginx、Hayproxy等七层负载均衡upstream指令该指令是用来定义一组服务器，它们可以是监听不同端口的服务器，并且也可以是同时监听TCP和Unix socket的服务器。服务器可以指定不同的权重，默认为1。| 语法 | upstream name {...} | | ------ | ------------------- | | 默认值 | — | | 位置 | http |upstream 变量{ server 192.168.200.146:9091; server 192.168.200.146:9092; server 192.168.200.146:9093; } server { listen 8083; server_name localhost; location /{ proxy_pass http://变量; } }服务器状态设置down:将该服务器标记为永久不可用，那么该代理服务器将不参与负载均衡。backup:将该服务器标记为备份服务器，当主服务器不可用时，将用来传递请求。max_conns=number:用来设置代理服务器同时活动链接的最大数量，默认为0，表示不限制，使用该配置可以根据后端服务器处理请求的并发量来进行设置，防止后端服务器被压垮。max_fails=number:设置允许请求代理服务器失败的次数，默认为1。fail_timeout=time:设置经过max_fails失败后，服务暂停的时间，默认是10秒。upstream 变量{ server 192.168.200.133:9001 down; server 192.168.200.133:9002 backup; server 192.168.200.133:9003 max_fails=3 fail_timeout=15; }负载均衡策略| 轮询 | 默认方式 | | ---------- | ---------------- | | weight | 权重方式 | | ip_hash | 依据ip分配方式 | | least_conn | 依据最少连接方式 | | url_hash | 依据URL分配方式 | | fair | 依据响应时间方式 |轮询是upstream模块负载均衡默认的策略。每个请求会按时间顺序逐个分配到不同的后端服务器。轮询不需要额外的配置。upstream 变量{ server 192.168.200.146:9001 weight=1; server 192.168.200.146:9002; server 192.168.200.146:9003; }weight加权[加权轮询]weight=number:用来设置服务器的权重，默认为1，权重数据越大，被分配到请求的几率越大。upstream 变量{ server 192.168.200.146:9001 weight=10; server 192.168.200.146:9002 weight=5; server 192.168.200.146:9003 weight=3; }ip_hash每个Ip只能连接对应的服务器upstream 变量{ ip_hash; server 192.168.200.146:9001; server 192.168.200.146:9002; server 192.168.200.146:9003; }least_conn最少连接，把请求转发给连接数较少的后端服务器。upstream 变量{ least_conn; server 192.168.200.146:9001; server 192.168.200.146:9002; server 192.168.200.146:9003; }url_hash每个url只能访问对应的服务器upstream 变量{ hash &request_uri; server 192.168.200.146:9001; server 192.168.200.146:9002; server 192.168.200.146:9003; }fairfair采用的不是内建负载均衡使用的轮换的均衡算法，而是可以根据页面大小、加载时间长短智能的进行负载均衡。那么如何使用第三方模块的fair负载均衡策略。upstream 变量{ fair; server 192.168.200.146:9001; server 192.168.200.146:9002; server 192.168.200.146:9003; }因为fair属于第三方模块实现的负载均衡。需要添加nginx-upstream-fair: 下载nginx-upstream-fair模块 下载地址为: https://github.com/gnosek/nginx-upstream-fair 将下载的文件上传到服务器并进行解压缩 unzip nginx-upstream-fair-master.zip 重命名资源 mv nginx-upstream-fair-master fair 使用./configure命令将资源添加到Nginx模块中 ./configure --add-module=/root/fair 在Nginx的源码中 src/http/ngx_http_upstream.h,找到ngx_http_upstream_srv_conf_s，在模块中添加添加default_port属性 in_port_t default_port 编译 make 将sbin目录下的nginx进行备份 mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginxold 将安装目录下的objs中的nginx拷贝到sbin目录 cd objs cp nginx /usr/local/nginx/sbin 更新Nginx cd ../ make upgrade四层负载均衡一般主要使用七层负载均衡,四层使用的较少stream指令该指令提供在其中指定流服务器指令的配置文件上下文。和http类似,但只能实现跳转和负载均衡。| 语法 | stream { ... } | | ------ | -------------- | | 默认值 | — | | 位置 | main |stream { upstream redisbackend { server 192.168.200.146:6379; server 192.168.200.146:6378; } upstream tomcatbackend { server 192.168.200.146:8080; } server { listen 81; proxy_pass redisbackend; } server { listen 82; proxy_pass tomcatbackend; } }Keepalived使用Keepalived来解决Nginx集群问题环境搭建环境准备| VIP | IP | 主机名 | 主/从 | | --------------- | --------------- | ----------- | ------ | | | 192.168.200.133 | keepalived1 | Master | | 192.168.200.222 | | | | | | 192.168.200.122 | keepalived2 | Backup |keepalived的安装步骤1:从官方网站下载keepalived,官网地址https://keepalived.org/ 步骤2:将下载的资源上传到服务器 keepalived-2.0.20.tar.gz 步骤3:创建keepalived目录，方便管理资源 mkdir keepalived 步骤4:将压缩文件进行解压缩，解压缩到指定的目录 tar -zxf keepalived-2.0.20.tar.gz -C keepalived/ 步骤5:对keepalived进行配置，编译和安装 cd keepalived/keepalived-2.0.20 ./configure --sysconf=/etc --prefix=/usr/local make && make install安装完成后，有两个文件需要我们认识下，一个是 /etc/keepalived/keepalived.conf(keepalived的系统配置文件，我们主要操作的就是该文件)，一个是/usr/local/sbin目录下的keepalived,是系统配置脚本，用来启动和关闭keepalivedKeepalived配置文件介绍打开keepalived.conf配置文件这里面会分三部，第一部分是global全局配置、第二部分是vrrp相关配置、第三部分是LVS相关配置。 本次课程主要是使用keepalived实现高可用部署，没有用到LVS，所以我们重点关注的是前两部分```global全局部分：global_defs { #通知邮件，当keepalived发送切换时需要发email给具体的邮箱地址 notification_email { tom@itcast.cn jerry@itcast.cn } #设置发件人的邮箱信息 notification_email_from zhaomin@itcast.cn #指定smpt服务地址 smtp_server 192.168.200.1 #指定smpt服务连接超时时间 smtp_connect_timeout 30 #运行keepalived服务器的一个标识，可以用作发送邮件的主题信息 router_id LVS_DEVEL#默认是不跳过检查。检查收到的VRRP通告中的所有地址可能会比较耗时，设置此命令的意思是，如果通告与接收的上一个通告来自相同的master路由器，则不执行检查(跳过检查) vrrp_skip_check_adv_addr #严格遵守VRRP协议。 vrrp_strict #在一个接口发送的两个免费ARP之间的延迟。可以精确到毫秒级。默认是0 vrrp_garp_interval 0 #在一个网卡上每组na消息之间的延迟时间，默认为0 vrrp_gna_interval 0 } ``````VRRP部分，该部分可以包含以下四个子模块1. vrrp_script2. vrrp_sync_group3. garp_group4. vrrp_instance我们会用到第一个和第四个，设置keepalived实例的相关信息，VI_1为VRRP实例名称vrrp_instance VI_1 { state MASTER #有两个值可选MASTER主 BACKUP备 interface ens33 #vrrp实例绑定的接口，用于发送VRRP包[当前服务器使用的网卡名称] virtual_router_id 51#指定VRRP实例ID，范围是0-255 priority 100 #指定优先级，优先级高的将成为MASTER advert_int 1 #指定发送VRRP通告的间隔，单位是秒 authentication { #vrrp之间通信的认证信息 auth_type PASS #指定认证方式。PASS简单密码认证(推荐) auth_pass 1111 #指定认证使用的密码，最多8位 } virtual_ipaddress { #虚拟IP地址设置虚拟IP地址，供用户访问使用，可设置多个，一行一个 192.168.200.222 } } ```配置内容如下:服务器1``` global_defs { #发生切换时发送邮箱通知notification_email { tom@itcast.cn jerry@itcast.cn } notification_email_from zhaomin@itcast.cn #设置邮箱发送者 smtp_server 192.168.200.1 #指定smpt服务地址 smtp_connect_timeout 30 #定义邮件发送超时时间 router_id keepalived1 #主机身份标识信息 vrrp_skip_check_adv_addr #跳过相邻地址 vrrp_strict #严格遵守VRRP协议 vrrp_garp_interval 0 #接口延迟 vrrp_gna_interval 0 #网卡延迟 }vrrp_instance VI_1 { state MASTER #keepalived角色描述信息 interface ens33 #将虚拟ip用于那块网卡 virtual_router_id 51 #实例ID priority 100 #优先级 advert_int 1 #主服务器组播包发送间隔时间 authentication { auth_type PASS #采用明文认证机制 auth_pass 1111 #明文密码 } virtual_ipaddress { 192.168.200.222 #设置虚拟ip地址信息 } } ```服务器2``` ! Configuration File for keepalivedglobal_defs { #发生切换时发送邮箱通知 notification_email { tom@itcast.cn jerry@itcast.cn } notification_email_from zhaomin@itcast.cn #设置邮箱发送者 smtp_server 192.168.200.1 #指定smpt服务地址 smtp_connect_timeout 30 #定义邮件发送超时时间 router_id keepalived2 #主机身份标识信息 vrrp_skip_check_adv_addr #跳过相邻地址 vrrp_strict #严格遵守VRRP协议 vrrp_garp_interval 0 #接口延迟 vrrp_gna_interval 0 #网卡延迟 }vrrp_instance VI_1 { state BACKUPR #keepalived角色描述信息 interface ens33 #将虚拟ip用于那块网卡 virtual_router_id 51 #实例ID priority 90 #优先级 advert_int 1 #主服务器组播包发送间隔时间 authentication { auth_type PASS #采用明文认证机制 auth_pass 1111 #明文密码 } virtual_ipaddress { 192.168.200.222 #设置虚拟ip地址信息 } } ```keepalived脚本keepalived只能做到对网络故障和keepalived本身的监控，即当出现网络故障或者keepalived本身出现问题时，进行切换。但是这些还不够，我们还需要监控keepalived所在服务器上的其他业务，比如Nginx,如果Nginx出现异常了，仅仅keepalived保持正常，是无法完成系统的正常工作的，因此需要根据业务进程的运行状态决定是否需要进行主备切换，这个时候，我们可以通过编写脚本对业务进程进行检测监控。实现步骤: 在keepalived配置文件中添加对应的配置像 vrrp_script 脚本名称 { script "脚本位置" interval 3 #执行时间间隔 weight -20 #动态调整vrrp_instance的优先级 } 编写脚本 ck_nginx.sh```!/bin/bashnum=ps -C nginx --no-header | wc -l if [ $num -eq 0 ];then /usr/local/nginx/sbin/nginx sleep 2 if [ ps -C nginx --no-header | wc -l -eq 0 ]; then killall keepalived fi fi ```Linux ps命令用于显示当前进程 (process) 的状态。-C(command) :指定命令的所有进程--no-header 排除标题 为脚本文件设置权限 chmod 755 ck_nginx.sh 将脚本添加到 vrrp_script ck_nginx { script "/etc/keepalived/ck_nginx.sh" #执行脚本的位置 interval 2 #执行脚本的周期，秒为单位 weight -20 #权重的计算方式 } vrrp_instance VI_1 { state MASTER interface ens33 virtual_router_id 10 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.200.111 } track_script { ck_nginx } } 如果效果没有出来，可以使用 tail -f /var/log/messages查看日志信息，找对应的错误信息。 测试 OpenResty指令|指令|指令值|作用| | - | - | -| |content_by_lua|"lua语法"|正常执行lua语法| |*content_by_lua_file|lua脚本路径|正常执行lua脚本| |init_by_lua|"lua语法"|启动前执行语法| |init_by_lua_file|lua脚本路径|启动前执行脚本| |init_worker_by_lua|"lua语法"|定时执行语法| |init_worker_by_lua_file|lua脚本路径|定时执行脚本| |set_by_lua|"lua语法"|正常执行,执行语法后结果以变量形式返回| |set_by_lua_file|lua脚本路径|正常执行,执行脚本后结果以变量形式返回| |rewrite_by_lua|"lua语法"|重定向时执行语法| |rewrite_by_lua_file|lua脚本路径|重定向时执行脚本| |access_by_lua|"lua语法"|内网访问时执行语法| |access_by_lua_file|lua脚本路径|内网访问时执行脚本| |header_filter_by_lua|"lua语法"|正常执行,lua语法结果返回到响应头信息| |header_filter_by_lua_file|lua脚本路径|正常执行,lua脚本结果返回到响应头信息| |body_filter_by_lua|"lua语法"|对响应数据进行过滤，如截断、替换| |body_filter_by_lua_file|lua脚本路径|对响应数据进行过滤，如截断、替换| |ssl_certificate_by_lua|"lua语法"|Nginx和下游服务开始一个SSL握手操作时将允许本配置项的Lua代码| |ssl_certificate_by_lua_file|lua脚本路径|Nginx和下游服务开始一个SSL握手操作时将允许本配置项的Lua代码|nginx location ~ /api/item/(\d+){ # 默认响应类型 default_type application/json; # 响应结果由lua/item.lua文件决定 content_by_lua_file lua/item.lua }
configure推荐:sh ./configure --with-http_gzip_static_module --with-http_ssl_module可选:sh ./configure --add-module=/root/nginx/module/purge --add-module=/root/fair with-http_gzip_static_module:压缩模块 --with-http_ssl_module:https模块 purge:清除缓存模块 fair:智能负载均衡模块 Nginx主配置```sh worker_processes auto; #并发数,与cpu内核相同 worker_rlimit_nofile 51200; #当前worker运行用户的最大文件打开数值 user 用户名 #设置用户名events{ use epoll; #nginx底层使用的函数 worker_connections 51200; #单个worker最大连接数 multi_accept on; #同时收到多个网络连接 }http{ include mime.types; #解析前端响应的资源server_names_hash_bucket_size 512; #服务器名大小限制512字节 client_header_buffer_size 32k; #请求头大小限制32k large_client_header_buffers 4 32k;#请求行+请求头限制4*32 client_max_body_size 50m; #最大上传文件 limit_conn_zone $binary_remote_addr zone=perip:10m; #限制同一ip并发连接数以及下载带宽 limit_conn_zone $server_name zone=perserver:10m; #$server_name是限制同一server并发连接数以及下载带宽 sendfile on; #使用sendflie()提升文件传输性 tcp_nopush on; #提高网络传输效率 tcp_nodelay on; #保证网络连接实效性 keepalive_timeout 60; #接超时时间 include proxy.conf; #导入反向代理配置 include gzip.conf #导入压缩配置 include /项目名称/*.conf; #导入具体项目的配置 }```反向代理配置nginx proxy_temp_path /www/server/nginx/proxy_temp_dir; #从代理服务器接收到的数据的临时文件定义目录 proxy_cache_path /www/server/nginx/proxy_cache_dir levels=1:2 keys_zone=cache_one:20m inactive=1d max_size=5g;#从代理服务器接收到的数据的缓存文件定义目录,有两层目录,缓存区为cache_one,1天内为访问就删除,最大缓存空间5g client_body_buffer_size 512k;#如果请求的值大于512小于就会将数据先存储到临时文件中 proxy_connect_timeout 60;#建立连接超时时间 proxy_read_timeout 60;#获取数据超时时间 proxy_send_timeout 60;#发送数据超时时间 proxy_buffer_size 32k;#被代理服务器响应头大小,不够会再申 proxy_buffers 4 64k;#被代理服务器响应体大小,4*64k,不够会再申 proxy_busy_buffers_size 128k; #在没有完全读完响应就开始传送数据 proxy_temp_file_write_size 128k;#设置同时写入临时文件的数据量的总大小 proxy_next_upstream error timeout invalid_header http_500 http_503 http_404;#发送503和404时重试 proxy_cache cache_one; #开启缓存,缓存名cache_one压缩配置nginx gzip on; #开启压缩 gzip_min_length 1k; #超过指定大小不压缩 gzip_buffers 4 16k; #压缩申请的空间数和大小 gzip_comp_level 5; #压缩等级,好点服务器可以用6 gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml; #压缩类型 gzip_vary on; #请求头显示已压缩 gzip_proxied expired no-cache no-store private auth; #根据请求头判断是否压缩 gzip_disable "MSIE [1-6]\."; #老版浏览器不压缩项目配置```nginx upstream 集群名{ server tomcatip:端口 weight=1; server tomcatip:端口; server tomcatip:端口; } server{ listen 80; #端口 listen 443 ssl http2; #使用ssl server_name 域名; #Ip/域名 index index.html; #默认打开的html root /home/用户/项目 ;#html路径limit_conn perserver 300; #限制同一server_name并发连接数 limit_conn perip 25; #限制同一ip并发连接数 limit_rate 512k; #限制下载带宽 ssl_certificate /home/用户/项目/.pem; #pew文件 ssl_certificate_key /home/用户/项目/.pem; #key文件 ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; #ssl使用的协议 #禁止访问的文件或目录 location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md){ return 404; } #SSL证书验证,浏览器会判断证书是否安全 location ~ \.well-known{ allow all; } #图片缓存30天 location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)${ expires 30d; } #js和css缓存12天 location ~ .*\.(js|css)?${ expires 12h; } location /uri { proxy_pass http://集群名/uri; #反向代理 proxy_set_header Host $host; #请求头带网站名 proxy_set_header X-Real-IP $remote_addr; #请求头带客户端ip proxy_set_header REMOTE-HOST $remote_addr;#请求头带客户端ip proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #用户真实Ip(用了代理就不能获取真实的) } location /uri { default_type application/json; #默认响应类型 content_by_lua_file lua/item.lua #响应结果由lua/item.lua文件决定 } ```
lua概述Lua是一种轻量、小巧的脚本语言，用标准C语言编写并以源代码形式开发。设计的目的是为了嵌入到其他应用程序中，从而为应用程序提供灵活的扩展和定制功能。特性跟其他语言进行比较，Lua有其自身的特点：（1）轻量级Lua用标准C语言编写并以源代码形式开发，编译后仅仅一百余千字节，可以很方便的嵌入到其他程序中。（2）可扩展Lua提供非常丰富易于使用的扩展接口和机制，由宿主语言(通常是C或C++)提供功能，Lua可以使用它们，就像内置的功能一样。（3）支持面向过程编程和函数式编程应用场景Lua在不同的系统中得到大量应用，场景的应用场景如下:游戏开发、独立应用脚本、web应用脚本、扩展和数据库插件、系统安全上。安装Linux安装在linux上安装Lua非常简单，只需要下载源码包并在终端解压、编译即可使用。Lua的官网地址为:https://www.lua.org 点击download可以找到对应版本的下载地址，我们本次课程采用的是lua-5.3.5,其对应的资源链接地址为https://www.lua.org/ftp/lua-5.4.1.tar.gz,也可以使用wget命令直接下载: wget https://www.lua.org/ftp/lua-5.4.1.tar.gz 编译安装 cd lua-5.4.1 make linux test make install如果在执行make linux test失败，报如下错误:说明当前系统缺少libreadline-dev依赖包，需要通过命令来进行安装yum install -y readline-devel验证是否安装成功lua -v运行命令式Lua交互式编程模式可以通过命令lua -i 或lua来启用:lua脚本式也可以通过将写好的lua代码文件执行sh lua hello.luavscode由于openrestry无法在vscode中运行,即脚本可以在vscode运行,但是无法获取到Nginx的参数,所以学习此方法无太大意义,仅用于测试lua脚本语法由于lua底层是由c编写,所以语法上和c极为相似注释单行注释的语法为：--注释内容多行注释的语法为:--注释内容 注释内容 --如果想取消多行注释，只需要在第一个--之前在加一个-即可，如：---注释内容 注释内容 --运算符Lua中支持的运算符有算术运算符、关系运算符、逻辑运算符、其他运算符。算术运算符:+ 加法 - 减法 * 乘法 / 除法 % 取余 ^ 乘幂 - 负号例如:10+20 -->30 20-10 -->10 10*20 -->200 20/10 -->2 3%2 -->1 10^2 -->100 -10 -->-10关系运算符``` == 等于 ~= 不等于大于 < 小于 = 大于等于 <= 小于等于 ```例如:10==10 -->true 10~=10 -->false 20>10 -->true 20<10 -->false 20>=10 -->true 20<=10 -->false逻辑运算符and 逻辑与 A and B && or 逻辑或 A or B || not 逻辑非 取反，如果为true,则返回false !逻辑运算符可以作为if的判断条件，返回的结果如下:``` A = true B = trueA and B -->true A or B -->true not A -->falseA = true B = falseA and B -->false A or B -->true not A -->falseA = false B = trueA and B -->false A or B -->true not A -->true```其他运算符``` .. 连接两个字符串返回字符串或表的长度```例如:```"HELLO ".."WORLD" -->HELLO WORLD"HELLO" -->5```全局变量&局部变量在Lua语言中，全局变量无须声明即可使用。在默认情况下，变量总是认为是全局的，如果未提前赋值，默认为nil:要想声明一个局部变量，需要使用local来声明Lua数据类型Lua有8个数据类型nil(空，无效值) boolean(布尔，true/false) number(数值) string(字符串) function(函数) table（表） thread(线程) userdata（用户数据）可以使用type函数测试给定变量或者的类型：print(type(nil)) -->nil print(type(true)) --> boolean print(type(1.1*1.1)) --> number print(type("Hello world")) --> string print(type(io.stdin)) -->userdata print(type(print)) --> function print(type(type)) -->function print(type{}) -->table print(type(type(X))) --> stringnilnil是一种只有一个nil值的类型，它的作用可以用来与其他所有值进行区分，也可以当想要移除一个变量时，只需要将该变量名赋值为nil,垃圾回收就会会释放该变量所占用的内存。booleanboolean类型具有两个值，true和false。boolean类型一般被用来做条件判断的真与假。在Lua语言中，只会将false和nil视为假，其他的都视为真，特别是在条件检测中0和空字符串都会认为是真，这个和我们熟悉的大多数语言不太一样。number在Lua5.3版本开始，Lua语言为数值格式提供了两种选择:integer(整型)和float(双精度浮点型)[和其他语言不太一样，float不代表单精度类型]。数值常量的表示方式:```4 -->4 0.4 -->0.4 4.75e-3 -->0.00475 4.75e3 -->4750 ```不管是整型还是双精度浮点型，使用type()函数来取其类型，都会返回的是number```type(3) -->number type(3.3) -->number ```所以它们之间是可以相互转换的，同时，具有相同算术值的整型值和浮点型值在Lua语言中是相等的stringLua语言中的字符串即可以表示单个字符，也可以表示一整本书籍。在Lua语言中，操作100K或者1M个字母组成的字符串的程序很常见。可以使用单引号或双引号来声明字符串```a = "hello" b = 'world' print(a) -->hello print(b) -->world ```如果声明的字符串比较长或者有多行，则可以使用如下方式进行声明``` html = Lua-string Lua ```table​ table是Lua语言中最主要和强大的数据结构。使用表， Lua 语言可以以一种简单、统一且高效的方式表示数组、集合、记录和其他很多数据结构。 Lua语言中的表本质上是一种辅助数组。这种数组比Java中的数组更加灵活，可以使用数值做索引，也可以使用字符串或其他任意类型的值作索引(除nil外)。创建表的最简单方式:```a = {} ```创建数组:​ 我们都知道数组就是相同数据类型的元素按照一定顺序排列的集合，那么使用table如何创建一个数组呢?```arr = {"TOM","JERRY","ROSE"} ```​ 要想获取数组中的值，我们可以通过如下内容来获取:print(arr[0]) nil print(arr[1]) TOM print(arr[2]) JERRY print(arr[3]) ROSE​ 从上面的结果可以看出来，数组的下标默认是从1开始的。所以上述创建数组，也可以通过如下方式来创建```arr = {} arr[1] = "TOM" arr[2] = "JERRY" arr[3] = "ROSE" ```上面我们说过了，表的索引即可以是数字，也可以是字符串等其他的内容，所以我们也可以将索引更改为字符串来创建```arr = {} arr["X"] = 10 arr["Y"] = 20 arr["Z"] = 30 ```当然，如果想要获取这些数组中的值，可以使用下面的方式``` 方式一print(arr["X"]) print(arr["Y"]) print(arr["Z"]) 方式二 print(arr.X) print(arr.Y) print(arr.Z) ```当前table的灵活不进于此，还有更灵活的声明方式```arr = {"TOM",X=10,"JERRY",Y=20,"ROSE",Z=30} ```如何获取上面的值?TOM : arr[1] 10 : arr["X"] | arr.X JERRY: arr[2] 20 : arr["Y"] | arr.Y ROESE?function在 Lua语言中，函数（ Function ）是对语句和表达式进行抽象的主要方式。定义函数的语法为:``` function functionName(params)end ```函数被调用的时候，传入的参数个数与定义函数时使用的参数个数不一致的时候，Lua 语言会通过 抛弃多余参数和将不足的参数设为 nil 的方式来调整参数的个数。``` function f(a,b) print(a,b) endf() --> nil nil f(2) --> 2 nil f(2,6) --> 2 6 f(2.6.8) --> 2 6 (8被丢弃) ```可变长参数函数``` function add(...) a,b,c=... print(a) print(b) print(c) endadd(1,2,3) --> 1 2 3 ```函数返回值可以有多个，这点和Java不太一样``` function f(a,b) return a,b endx,y=f(11,22) --> x=11,y=22```threadthread翻译过来是线程的意思，在Lua中，thread用来表示执行的独立线路，用来执行协同程序。userdatauserdata是一种用户自定义数据，用于表示一种由应用程序或C/C++语言库所创建的类型。Lua控制结构Lua 语言提供了一组精简且常用的控制结构，包括用于条件执行的证 以及用于循环的 while、 repeat 和 for。 所有的控制结构语法上都有一个显式的终结符： end 用于终结 if、 for 及 while 结构， until 用于终结 repeat 结构。if then elseif elseif语句先测试其条件，并根据条件是否满足执行相应的 then 部分或 else 部分。 else 部分 是可选的。``` function testif(a) if a>0 then print("a是正数") end endfunction testif(a) if a>0 then print("a是正数") else print("a是负数") end end ```如果要编写嵌套的 if 语句，可以使用 elseif。 它类似于在 else 后面紧跟一个if。根据传入的年龄返回不同的结果，如``` age<=18 青少年， age>18 , age <=45 青年 age>45 , age<=60 中年人 age>60 老年人function show(age) if age<=18 then return "青少年" elseif age>18 and age<=45 then return "青年" elseif age>45 and age<=60 then return "中年人" elseif age>60 then return "老年人" end end ```while循环顾名思义，当条件为真时 while 循环会重复执行其循环体。 Lua 语言先测试 while 语句 的条件，若条件为假则循环结束；否则， Lua 会执行循环体并不断地重复这个过程。语法：while 条件 do 循环体 end例子:实现数组的循环function testWhile() local i = 1 while i<=10 do print(i) i=i+1 end endrepeat循环顾名思义， repeat-until语句会重复执行其循环体直到条件为真时结束。 由于条件测试在循环体之后执行，所以循环体至少会执行一次。语法repeat 循环体 until 条件function testRepeat() local i = 10 repeat print(i) i=i-1 until i < 1 endfor循环数值型for循环语法for param=exp1,exp2,exp3 do 循环体 endparam的值从exp1变化到exp2之前的每次循环会执行 循环体，并在每次循环结束后将步长(step)exp3增加到param上。exp3可选，如果不设置默认为1for i = 1,100,10 do print(i) end泛型for循环泛型for循环通过一个迭代器函数来遍历所有值，类似于java中的foreach语句。语法for i,v in ipairs(x) do 循环体 endi是数组索引值，v是对应索引的数组元素值，ipairs是Lua提供的一个迭代器函数，用来迭代数组，x是要遍历的数组。例如:arr = {"TOME","JERRY","ROWS","LUCY"} for i,v in ipairs(arr) do print(i,v) end上述实例输出的结果为1 TOM 2 JERRY 3 ROWS 4 LUCY但是如果将arr的值进行修改为arr = {"TOME","JERRY","ROWS",x="JACK","LUCY"}同样的代码在执行的时候，就只能看到和之前一样的结果，而其中的x为JACK就无法遍历出来，缺失了数据，如果解决呢?我们可以将迭代器函数变成pairs,如for i,v in pairs(arr) do print(i,v) end上述实例就输出的结果为1 TOM 2 JERRY 3 ROWS 4 LUCY x JACKLua导入模块require安装openrestry后,require支持导入外部模块语法local 变量 = require('文件名')new对象本地文件lua不需要解析,只要导入外部模块时,需要解析local 对象 = require('文件名') local 变量 = 对象:new()Nginx函数以下介绍常用的ngx函数,更多操作可百度或者查看https://www.cnblogs.com/JohnABC/p/6182915.html| 函数 | 作用 | | -------------------------------------------------- | ------------------------------------------------------------ | | ngx.say() | 向Nginx返回结果,等效Nginx的Return,直接向前端返回 | | ngx.log(级别,..) | 将信息输出到error.log | | ngx.ERR | 错误级别 | | ngx.NOTICE | 正常级别 | | print(..) | 等效与ngx.log(ngx.NOTICE, ...) | | ngx.exit(状态码) | 返回状态码 | | ngx.req.get_uri_args() | 获取路径参数,多用于获取GET参数 | | ngx.req.get_uri_args() | 获取请求头 | | ngx.req.read_body() | 获取请求体,多用于获取POST参数和json | | ngx.var[1] | nginx中location正则表达式匹配数据,location ~ /item/api/(d+){...},其中()匹配的值进入var,多用于获取路径参数 | | ngx.shared.item_cache | 获取本地缓存对象 | | ngx.location.capture(uti,{method=方法,args=参数}) | 发送http请求 |发送http请求lua local function read_http(path, params) local resp = ngx.location.capture(path,{ method = ngx.HTTP_GET, args = params, }) if not resp then -- 记录错误信息，返回404 ngx.log(ngx.ERR, "http not found, path: ", path , ", args: ", args) ngx.exit(404) end return resp.body end外部模块Redis| 函数 | 作用 | | -------------------------------------------- | ----------------------------- | | red:set_timeout(建立,发送,接收) | 设置超时时间,单位毫秒 | | red:set_keepalive(连接的空闲时间,连接池大小) | 设置连接池,并归还连接 | | red:close() | 释放对象,使用连接池就不能使用 | | red:connect(ip, 端口) | 连接redis | | red:get(键) | 从redis获取值 | | red:set(键,值) | 存值到redis |```lua local redis = require('resty.redis') --导入redis local red = redis:new() --创建redis对象 redis:set_timeout(1000,1000,1000) --单位毫秒,建立请求超时时间,发送超时时间,响应超时时间--释放redis,归还至连接池 local function close_redis(red) local ok, err = red:set_keepalive(10000, 100) --归还至连接池,空闲时间100000毫秒,连接池数100 if not ok then ngx.log(ngx.ERR, "放入redis连接池失败: ", err) --向error.log输出错误信息 end end-- 查询redis的方法 ip和port是redis地址，key是查询的key local function read_redis(ip, port, key) local ok, err = red:connect(ip, port) -- 获取一个连接if not ok then ngx.log(ngx.ERR, "连接redis失败 : ", err)--向error.log输出错误信息 return nil end local resp, err = red:get(key) --获取值 if not resp then ngx.log(ngx.ERR, "查询Redis失败: ", err, ", key = " , key)--向error.log输出错误信息 end --得到的数据为空处理 if resp == ngx.null then resp = nil ngx.log(ngx.ERR, "查询Redis数据为空, key = ", key) --向error.log输出错误信息 end close_redis(red) --释放redis,归还至连接池 return resp --返回结果 endreturn read_redis ```Mysql一般不建议在nginx使用mysql,这里作为了解即可| 函数 | 作用 | | ------------------------------------------------------------ | ------------------------------------------ | | db:connect({host="ip", port=端口, user="用户", password="密码", database="表"}) | 接到MySQL服务器 | | db:set_timeout(建立,发送,接收) | 设置超时时间,单位毫秒 | | db:send_query("sql语法") | 发送sql语句 | | db:read_result(数值) | 从MySQL服务器返回结果中读取n行数据,默认为4 | | db:close() | 关闭当前MySQL连接 |```lua local mysql = require('resty.mysql') --导入redis local db = mysql:new() --创建redis对象local function read_mysql(sql,row) local ok,err = db:connect{ host="192.168.200.111", port=3306, user="root", password="123456", database="nginx_db" } --建立连接 db:set_timeout(1000) --设置超时时间 db:send_query(sql)--发送sql local res,err,errcode,sqlstate = db:read_result(row) --获取结果 db:close() --关闭连接 return res; end return read_mysql ```cjson| 函数 | 作用 | | ------------------ | ----------------- | | cjson.decode(json) | json转table | | cjson.encode(值) | table转json```lua |```lua local cjson = require('cjson') --导入cjsonarg1 = {xx=1}; arg2 = {yy=2};arg3.xx = arg1.xx; arg3.yy = arg2.yy;argJson = cjson.encode(arg3)ngx.say(argJson) ```