kk Blog —— 通用基础


date [-d @int|str] [+%s|"+%F %T"]
netstat -ltunp
sar -n DEV 1

Nginx Openresty - 读取请求体

https://blog.csdn.net/trustnature/article/details/94417336

由于nginx默认不读取请求体的数据,因此当 Lua 通过 ngx.var.request_body 的方式获取请求体时会发现数据为空,那么,该如何获得请求体的数据呢?

方式一:lua_need_request_body

1
2
3
4
5
语法:lua_need_request_body<on|off>

默认值:off

环境:http、server、location、

含义:默认为off,即不读取请求体。如果设置为on,则表示强制读取请求体,此时,可以通过 ngx.var.request_body 来获取请求体的数据。但需要注意一种情况,$request_body 存在与内存中,如果它的字节大小超过Nginx配置的 client_body_buffer_size 的值,Nginx就会把请求体存放到临时文件中。此时数据就不存在与内存中了,这会导致 $request_body 为空,所以需要设置 client_body_buffer_size 和 client_max_body_size 的值相同,避免出现这种情况。

这种配置方式不够灵活,Ngx_Lua官网也不推荐使用此方法。

方式二:ngx.req.read_body

1
2
3
语法:ngx.req.read_body()

环境:rewrite_by_lua*、access_by_lua*、content_by_lua*

含义:同步读取客户端请求体,且不会阻塞Nginx的事件循环。使用此指令后,就可以通过 ngx.req.get_body_data 来获取请求体的数据了。按如果使用临时文件来存放请求体,就需要先使用函数 ngx.req.get_body_file 来获取临时文件名,再读取临时文件中的请求体数据。

1
2
3
4
5
指令:ngx.req.get_body_data

语法:data = ngx.req.get_body_data()

环境:rewrite_by_lua*、access_by_lua*、content_by_lua*、log_by_lua*

含义:执行 ngx.req.read_body 指令后,可以使用本指令在内存中获取请求体数据,结果会返回一个Lua的字符串类型数据。如果要获取Lua的table类型的数据,则需要使用 ngx.req.get_post_args

1
2
3
4
5
指令:ngx.req.get_post_data

语法:args,err=ngx.req.get_post_args(max_args?)

环境:rewrite_by_lua*、access_by_lua*、content_by_lua*、header_filter_by_lua*、body_filter_by_lua*、log_by_lua*

含义:在执行 ngx.req.read_body 指令后,可以使用本指令读取包含当前请求在内的所有POST值请求的查询参数,返回一个Lua的table类型的数据。max_args 参数的作用时限制参数的数量。为了服务的安全,最多支持使用100个参数(包括重复的参数),超过限制的参数会被忽略。如果max_args为0,则表示关闭此限制;但为了避免被无穷多的参数攻击,不要将max_args设置为0,如果最多支持使用10个参数,则应配置为 ngx.req.get_post_args(10)。

使用场景:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
content_by_lua_block {
	local ngx = require "ngx"
	ngx.req.read_body()
	local data = ngx.req.get_body_data()
	if data then
		ngx.print('ngx.req.get_body_data:',data,')
		return
	else
		lcoal file = ngx.req.get_body_file()
		if file then
			ngx.say("body is in file",file)
		else
			ngx.say("no body found")
		end
	end
}

Nginx 安装 Lua 支持

Nginx 支持 Lua 需要安装 lua-nginx-module 模块,一般常用有 2 种方法:

编译 Nginx 的时候带上 lua-nginx-module 模块一起编译

使用 OpenResty: Nginx + 一些模块,默认启用了 Lua 支持(推荐使用此方式)


OpenResty is just an enhanced version of Nginx by means of addon modules anyway. You can take advantage of all the exisitng goodies in the Nginx world.

OpenResty® 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。

OpenResty® 通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将 Nginx 有效地变成一个强大的通用 Web 应用平台。这样,Web 开发人员和系统工程师可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高性能 Web 应用系统。

OpenResty® 的目标是让你的Web服务直接跑在 Nginx 服务内部,充分利用 Nginx 的非阻塞 I/O 模型,不仅仅对 HTTP 客户端请求,甚至于对远程后端诸如 MySQL、PostgreSQL、Memcached 以及 Redis 等都进行一致的高性能响应。

OpenResty

OpenResty 的安装很方便,对于一些常见的 Linux 发行版本,OpenResty® 提供 官方预编译包,CentOS 使用 yum,Ubuntu 使用 apt-get,具体请参考 https://openresty.org/cn/installation.html%EF%BC%8C%E4%BB%A5%E4%B8%8B%E4%BB%A5CentOS 7 中安装 OpenResty 为例。

CentOS 7 使用 OpenResty

终端执行下面 3 条命令把 OpenResty 安装到 /usr/local/openresty

1
2
3
4
5
sudo yum install yum-utils

sudo yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo

sudo yum install openresty

Nginx 的配置文件位于 /usr/local/openresty/nginx/conf/nginx.conf (openresty -V 中没有指定)

验证

/usr/local/nginx/conf/nginx.conf 中添加 Lua 测试代码

1
2
3
4
location /lua {
	default_type 'text/html';
	content_by_lua 'ngx.say("hello world");';
}

启动 openresty

1
openresty

curl http://localhost/lua 输出 hello world 则说明 Nginx 支持 Lua

help

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@localhost ~]# openresty -h
nginx version: openresty/1.21.4.1
Usage: nginx [-?hvVtTq] [-s signal] [-p prefix]
             [-e filename] [-c filename] [-g directives]

Options:
  -?,-h         : this help
  -v            : show version and exit
  -V            : show version and configure options then exit
  -t            : test configuration and exit
  -T            : test configuration, dump it and exit
  -q            : suppress non-error messages during configuration testing
  -s signal     : send signal to a master process: stop, quit, reopen, reload
  -p prefix     : set prefix path (default: /usr/local/openresty/nginx/)
  -e filename   : set error log file (default: logs/error.log)
  -c filename   : set configuration file (default: conf/nginx.conf)
  -g directives : set global directives out of configuration file

编译 Nginx + Lua

编译 Nginx 需要先准备好下面的这些工具,如果不确定是否已安装,可以在编译的时候根据出现的错误提示再进行安装

1
2
yum install -y gcc g++ gcc-c++
yum -y install zlib zlib-devel openssl openssl--devel pcre pcre-devel

Nginx 支持 Lua 需要依赖 LuaJIT-2.0.4.tar.gz,ngx_devel_kit,lua-nginx-module,下面介绍具体的编译过程 (都下载到 /root 目录)

下载安装 LuaJIT-2.0.4.tar.gz

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
wget -c http://luajit.org/download/LuaJIT-2.0.4.tar.gz
tar xzvf LuaJIT-2.0.4.tar.gz
cd LuaJIT-2.0.4
make install PREFIX=/usr/local/luajit

# 添加环境变量
export LUAJIT_LIB=/usr/local/luajit/lib
export LUAJIT_INC=/usr/local/luajit/include/luajit-2.0

下载解压 ngx_devel_kit

wget https://github.com/simpl/ngx_devel_kit/archive/v0.3.0.tar.gz
tar -xzvf v0.3.0.tar.gz

下载解压 lua-nginx-module
wget https://github.com/openresty/lua-nginx-module/archive/v0.10.8.tar.gz
tar -xzvf v0.10.8.tar.gz

下载安装 nginx-1.10.3.tar.gz

wget http://nginx.org/download/nginx-1.10.3.tar.gz
tar -xzvf nginx-1.10.3.tar.gz
cd nginx-1.10.3

# 注意ngx_devel_kit和lua-nginx-module 以实际解压路径为准
./configure --add-module=/root/ngx_devel_kit-0.3.0 --add-module=/root/lua-nginx-module-0.10.8

make -j2
make install

支持 Nginx 被安装到了 /usr/local/nginx,配置文件为 /usr/local/nginx/conf/nginx.conf

验证

将 nginx 做成命令: ln -s /usr/local/nginx/sbin/nginx /usr/bin/nginx

/usr/local/nginx/conf/nginx.conf 中添加 Lua 测试代码

1
2
3
4
location /lua {
	default_type 'text/html';
	content_by_lua 'ngx.say("hello world");';
}

启动 openresty

1
openresty

curl http://localhost/lua 输出 hello world 则说明 Nginx 支持 Lua

上面编译 Nginx 的内容来源于 http://www.cnblogs.com/aoeiuv/p/6856056.html%EF%BC%8C%E7%BC%96%E8%AF%91 Nginx 相对使用 OpenResty 麻烦一些,不过也不难,根据自己的喜好选择即可。

http://qtdebug.com/mac-nginx-lua/

nignx的proxy_set_header快速理解

https://www.cnblogs.com/eastegg/p/16650586.html

客户端地址(请求服务的地址):192.168.1.1

nignx服务器地址:192.168.1.2

后端服务器地址:192.168.1.3

proxy_set_header设置请求头,以便于后端服务器可以获取以上实际信息。

一、X-Real-IP

是指客户端的真实IP,如果设置了$remote_addr这个值,后端服务器就能获取到客户端的真实IP,也就是此例中的192.168.1.1

二、Host

proxy_set_header 可以设置 Host 为 $proxy_host、$host 与 $http_host。

host 的值设置为 $proxy_host,是指 nginx.conf 的 proxy_pass 中设置的host值,也就是192.168.1.3,也就是服务器的IP地址。

$http_host 不是一个固定的变量,他其实是 $http_HEADER 通配后的结果。

$http_HEADER,注意,这里的 HEADER 是一个通配符,通配的是请求头里的 header 属性,例如 $http_content_type 表示请求头里 content-type 属性的值,同理,$http_host 指的就是请求头里的host属性。

$host 是 core 模块内部的一个变量。

当请求头里不存在 Host 属性或者是个空值,$host 则等于 server_name

如果请求头里有Host属性,那么 $host 等于 Host 属性除了端口号的部分,例如 Host 属性是 www.example.com,那么$host就是 www.example.com

变量 是否显示端口 值是否存在
host "Host:value"显示
值为a:b的时候,只显示a
http_host "Host:value",value存在就显示
proxy_host 默认80不显示
其他端口显示
"Host:value"显示

参考:nginx $host$http_host 的区别 - UCloud云社区
https://zhuanlan.zhihu.com/p/115731015
Nginx中$http_host、$host、$proxy_host的区别 - hopeless-dream - 博客园 (cnblogs.com)

三、X-Forwarded-For

这个变量的值有 $proxy_add_x_forwarded_for 和 $remote_addr,在只有一个代理服务器的转发的情况下,两者的效果貌似差不多,都可以真实的显示出客户端原始ip。

举例说明,用户A的IP是192.168.1.1,请求一个经过两次nginx转发的应用,在第一台nginx中(192.168.1.2),配置如下:

1
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

现在 $proxy_add_x_forwarded_for 变量的"X-Forwarded-For"部分是空的,所以只有$remote_addr,而$remote_addr的值是用户的ip,那么X-Forwarded-For变量的值就是用户的ip:192.168.1.1。

到第二台nginx,配置如下:

1
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

现在的$proxy_add_x_forwarded_for变量,X-Forwarded-For部分包含的是用户的真实ip,$remote_addr部分的值是上一台nginx的ip地址,那么X-Forwarded-For的值就变成了"用户的真实ip,第一台nginx的ip",也就是“192.168.1.1, 192.168.1.2”

所以还是建议 X-Forwarded-For 的值设置成 $proxy_add_x_forwarded_for。

参考:https://cloud.tencent.com/developer/article/1899717