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再次转发重试就会造成重复写入的问题。
- Windows Server 2008群集仲裁机制
- [C#2] 5-迭代器
- 服务器未能识别 HTTP 标头 SOAPAction 的值
- 实用代码-C#获取本机网络适配器信息及MAC地址
- WordPress 自定义 login (登录页面)CSS 样式
- [C#1] 12-特性
- HTTP Basic Authentication for RESTFul Service
- [C#2] 4-可空类型、静态类
- jquery 操作css 尺寸
- Windows 7上IIS出现http 500错误
- [C#2] 2-匿名方法
- jquery 操作css 选择器
- 主页后台源码及释义
- [C#2] 3-局部类型、属性访问器保护级别、命名空间别名限定符
- 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 数组属性和方法
- PHP钩子实现方法解析
- 浅谈numpy中函数resize与reshape,ravel与flatten的区别
- PHP文件类型检查及fileinfo模块安装使用详解
- PHP封装的分页类与简单用法示例
- ThinkPHP3.2框架自带分页功能实现方法示例
- PHP获取访问设备信息的方法示例
- PHP实现微信提现功能
- PHP实现微信退款功能
- PHP利用pdo_odbc实现连接数据库示例【基于ThinkPHP5.1搭建的项目】
- PHP登录验证功能示例【用户名、密码、验证码、数据库、已登陆验证、自动登录和注销登录等】
- 实现php删除链表中重复的结点
- Yii2.0框架实现带分页的多条件搜索功能示例
- 定位地理位置PHP判断员工打卡签到经纬度是否在打卡之内
- PHP APP微信提现接口代码
- thinkPHP5.1框架路由::get、post请求简单用法示例