nginx 常见问题记录
一、location 中的 if 地狱
Directive if has problems when used in location context, in some cases it doesn’t do what you expect but something completely different instead. In some cases it even segfaults. It’s generally a good idea to avoid it if possible.
The only 100% safe things which may be done inside if in a location context are:
return ...;
rewrite ... last;
官方文档指明,location if语句中只有实用return 和 rewrite指令是绝对安全的。但是如果某些情况必须使用if 语句进行条件判断怎么办呢?需要记住一下几点:
- 当多个if条件判断同时满足时,只有最后一个if中的语句会被执行。因此若匹配前一个if语句后,不希望再往下继续匹配时,需要使用break结束;
- proxy_pass 和 try_files 可能因为if语句不能正常执行;
- nginx中不支持else、&& 和 || 语法,另外,nginx中if 语句也不支持嵌套,需要使用变量来构造;
二、access_log 和 error_log的路径能否使用变量?
某些场景下我们需要根据条件来区分nginx日志打印的路径,首先想到的就是能否使用如下语句呢?
access_log /home/path/${server_name}.access.log;
在高版本的nginx中允许access_log中使用变量,但是会有如下限制:
- 日志文件用“工作进程”创建,所以需要在日志目录有创建文件的权限。
- 无法使用写入缓冲。
- 由于经常使用的文件描述符会被缓存,在指令open_log_file_cache的参数valid指定的时间内,还会写入旧文件中。
- 每次写入日志时,会检查root目录是否存在。不存在,则不会创建日志。
简而言之,日志存在无法写入的可能,并且由于没有写入缓存,在请求量较大的场景会造成性能问题。
因此并不建议在access_log的路径中使用变量名。那怎样才能满足分不同路径打印的需求呢?access_log 支持可选参数 if=condition, 例如下面的官方例子,当返回码为2xx或3xx时不会打印日志,其他情况下的日志会打印到/path/to/access.log文件中:
map $status $loggable {
~^[23] 0;
default 1;
}
access_log /path/to/access.log combined if=$loggable;
error_log 路径不支持变量。变量一般是在http请求中使用,而error_log并不限于http请求使用,且应该保证所有关键的错误日志都能打印成功,便于定位问题。
三、自定义头部写法规范
在nginx中使用自定义头部不限制字母的大小写,但需要注意尽量使用中划线,若在必须使用下划线的情况下,需要设置 underscores_in_headers on;否则nginx会认为该头部不合法,由 ignore_invalid_headers 指令判断是否忽略该头部。
nginx读取自定义头部的变量为$http_{name}, name为头部名称的小写,且用下划线代替中划线即可。
四、慎用proxy_next_upstream
在不了解proxy_next_upstream机制时可能会踩到很多坑,比如服务出现了错误或超时,nginx却没有按照预期自动进行重试;或者类似创建订单或支付类的写接口,客户端明明只发送了一次请求,却因为nginx的重试,后台创建了多个相同的订单而引发线网问题等。
proxy_next_upstream指令指明了请求在什么情况会被重新发送到另外的server。
默认只有当连接上游服务出错或者超时时会重试,若需要对某些特定的http状态码进行重试,则需要指定http_500、http_404等。
但是通常情况下POST, LOCK, PATCH方法不会被转发到另一台server重试,需要显示设置non_idempotent才行。
但是生产环境一般不建议开启non_idempotent,无论是timeout还是http_500都可能是后台已经接受过一次请求了,若nginx再次转发重试就会造成重复写入的问题。
- 实用小工具,教你轻松转化Python通用数据格式
- 数据工程师常用的几个小工具(附python源代码)
- R语言的三种聚类方法
- 技能 | R语言的igraph画社交关系图示例
- 魔兽世界中招:一条命令行就能劫持你的游戏!
- R语言 apply函数家族详解
- 基于R语言的梯度推进算法介绍
- R语言数据可视化综合指南
- 关于CLR内存管理一些深层次的讨论[上篇]
- 关于CLR内存管理一些深层次的讨论[下篇]
- Python渗透工具的架构探讨
- 提供第三种代码生成方式——通过自定义BuildProvider为ASP.NET提供代码生成
- 小心,Android木马工具SpyNote免费啦!远程监听就是这么简单
- R语言的kmeans客户细分模型聚类
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 如何使用ParamSpider在Web文档中搜索敏感参数
- Spring 的 Controller 是单例还是多例?怎么保证并发的安全
- 《剑指offer》第28天:最长上升子序列(高频)
- 《剑指offer》第27天:三角形最小路径和
- 《剑指offer》第26天:最大子序和
- Threat Dragon:一款针对OWASP的威胁模型构建平台
- 《剑指offer》第25天:最简单的动态规划
- 基于web页面开发串口程序界面---html代码
- Debotnet:一款针对Windows10隐私设置和数据的保护工具
- 基于web页面开发串口程序界面---代码实现
- 《剑指offer》第24天:链表相加
- 《剑指offer》第23天:删除链表倒数第N个节点
- 《剑指offer》第22天:链表成环的新解法
- 一文入门Android逆向
- 安全研究 | Slack桌面应用程序的RCE漏洞+XSS漏洞