nginx 模块相关配置及结构理解

news2024/9/24 18:05:34

文章目录

  • 模块配置结构
  • 模块配置指令
    • 先看一下 ngx_command_t 结构
    • 一个模块配置的demo
    • 简单模块配置的案例演示
  • 模块上下文结构
  • 模块的定义

模块配置结构

Nginx中每个模块都会提供一些指令,以便于用户通过配置去控制该模块的行为。
Nginx的配置信息分成了几个作用域(scope,有时也称作上下文)。作用域有main, server, 以及location。

模块配置指令

先看一下 ngx_command_t 结构

位置: src/core 目录下 ngx_conf_file.h
ngx_command_t原型:

typedef struct ngx_command_s         ngx_command_t;
struct ngx_command_s {
    ngx_str_t             name;		// 配置指令名称
    ngx_uint_t            type;		// 该配置的类型,其实更准确一点说,是该配置指令属性的集合。(具体见下文)
    char               *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);	// (具体见下文)
    ngx_uint_t            conf;		/*该字段被NGX_HTTP_MODULE类型模块所用 
							    (我们编写的基本上都是NGX_HTTP_MOUDLE,只有一些nginx核心模块是非NGX_HTTP_MODULE),
							    该字段指定当前配置项存储的内存位置。实际上是使用哪个内存池的问题。
							    因为http模块对所要保存的配置信息,划分了main, server和location三个地方进行存储,
							    每个地方都有一个内存池用来分配存储这些信息的内存。
							    这里可能的值为 NGX_HTTP_MAIN_CONF_OFFSET、NGX_HTTP_SRV_CONF_OFFSET
							    或NGX_HTTP_LOC_CONF_OFFSET。
								    当然也可以直接置为0,就是NGX_HTTP_MAIN_CONF_OFFSET。*/
    ngx_uint_t            offset;	/*指定该配置项值的精确存放位置,一般指定为某一个结构体变量的字段偏移。
							    因为对于配置信息的存储,一般我们都是定义个结构体来存储的。
							    那么比如我们定义了一个结构体A,该项配置的值需要存储到该结构体的b字段。
							    那么在这里就可以填写为offsetof(A, b)。
							    对于有些配置项,它的值不需要保存或者是需要保存到更为复杂的结构中时,这里可以设置为0。*/
    void                 *post;		/* 该字段存储一个指针。可以指向任何一个在读取配置过程中需要的数据,
    								   以便于进行配置读取的处理。大多数时候,都不需要,所以简单地设为0即可。*/
};

补充说明:
1)对type字段
nginx提供了很多预定义的属性值(一些宏定义),通过逻辑或运算符可组合在一起,形成对这个配置指令的详细的说明。
属性值可以有

NGX_CONF_NOARGS:配置指令不接受任何参数。
NGX_CONF_TAKE1:配置指令接受1个参数。
NGX_CONF_TAKE2:配置指令接受2个参数。
NGX_CONF_TAKE3:配置指令接受3个参数。
NGX_CONF_TAKE4:配置指令接受4个参数。
NGX_CONF_TAKE5:配置指令接受5个参数。
NGX_CONF_TAKE6:配置指令接受6个参数。
NGX_CONF_TAKE7:配置指令接受7个参数。
可以组合多个属性,比如一个指令即可以不填参数,也可以接受1个或者2个参数。那么就是
NGX_CONF_NOARGS|NGX_CONF_TAKE1|NGX_CONF_TAKE2。

nginx还提供了一些定义,使用起来更简洁:

NGX_CONF_TAKE12:配置指令接受1个或者2个参数。
NGX_CONF_TAKE13:配置指令接受1个或者3个参数。
NGX_CONF_TAKE23:配置指令接受2个或者3个参数。
NGX_CONF_TAKE123:配置指令接受1个或者2个或者3参数。
NGX_CONF_TAKE1234:配置指令接受1个或者2个或者3个或者4个参数。
NGX_CONF_1MORE:配置指令接受至少一个参数。
NGX_CONF_2MORE:配置指令接受至少两个参数。
NGX_CONF_MULTI:配置指令可以接受多个参数,即个数不定。
NGX_CONF_BLOCK:配置指令可以接受的值是一个配置信息块。也就是一对大括号括起来的内容。里面可以再包括很多的配置指令。比如常见的server指令就是这个属性的。
NGX_CONF_FLAG:配置指令可以接受的值是”on”或者”off”,最终会被转成bool值。
NGX_CONF_ANY:配置指令可以接受的任意的参数值。一个或者多个,或者”on”或者”off”,或者是配置块。
需要说明的是,无论如何,nginx的配置指令的参数个数不可以超过NGX_CONF_MAX_ARGS个。目前这个值被定义为8,也就是不能超过8个参数值。

下面介绍一组说明配置指令作用域的相关属性:

NGX_DIRECT_CONF:可以出现在配置文件中最外层。例如已经提供的配置指令daemon,master_process等。
NGX_MAIN_CONF:http、mail、events、error_log等。
NGX_ANY_CONF:该配置指令可以出现在任意配置级别上。
对于我们编写的大多数模块而言,都是在处理http相关的事情,也就是所谓的都是NGX_HTTP_MODULE,对于这样类型的模块,其配置可能出现的位置也是分为直接出现在http里面,以及其他位置:
NGX_HTTP_MAIN_CONF: 可以直接出现在http配置指令里。
NGX_HTTP_SRV_CONF:可以出现在http里面的server配置指令里。
NGX_HTTP_LOC_CONF:可以出现在http server块里面的location配置指令里。
NGX_HTTP_UPS_CONF:可以出现在http里面的upstream配置指令里。
NGX_HTTP_SIF_CONF:可以出现在http里面的server配置指令里的if语句所在的block中。
NGX_HTTP_LMT_CONF:可以出现在http里面的limit_except指令的block中。
NGX_HTTP_LIF_CONF:可以出现在http server块里面的location配置指令里的if语句所在的block中。

2)对set字段
这是一个函数指针,当nginx在解析配置的时候,如果遇到这个配置指令,将会把读取到的值传递给这个函数进行分解处理。因为具体每个配置指令的值如何处理,只有定义这个配置指令的人是最清楚的。
函数原型:

// 处理成功时,返回NGX_OK,否则返回NGX_CONF_ERROR或者是一个自定义的错误信息的字符串。
/* cf: 该参数里面保存从配置文件读取到的原始字符串以及相关的一些信息。特别注意的是这个参数的args字段是一个ngx_str_t
类型的数组,
	   该数组的首个元素是这个配置指令本身,第二个元素是指令的第一个参数,第三个元素是第二个参数,依次类推。*/
/* cmd:  这个配置指令对应的ngx_command_t结构。*/
/* conf: 就是定义的存储这个配置值的结构体,用户在处理的时候可以使用类型转换,转换成自己知道的类型,再进行字段的赋值。*/
char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);

为了更加方便的实现对配置指令参数的读取,nginx已经默认提供了对一些标准类型的参数进行读取的函数,可以直接赋值给set字段使用。
下面列出这些已经实现的set类型函数:

ngx_conf_set_flag_slot:读取NGX_CONF_FLAG类型的参数。
ngx_conf_set_str_slot:读取字符串类型的参数。
ngx_conf_set_str_array_slot:读取字符串数组类型的参数。
ngx_conf_set_keyval_slot:读取键值对类型的参数。
ngx_conf_set_num_slot:读取整数类型(有符号整数ngx_int_t)的参数。
ngx_conf_set_size_slot:读取size_t类型的参数,也就是无符号数。
ngx_conf_set_off_slot:读取off_t类型的参数。
ngx_conf_set_msec_slot: 读取毫秒值类型的参数。
ngx_conf_set_sec_slot:读取秒值类型的参数。
ngx_conf_set_bufs_slot:读取的参数值是2个,一个是buf的个数,一个是buf的大小。例如: output_buffers 1 128k;
ngx_conf_set_enum_slot:读取枚举类型的参数,将其转换成整数ngx_uint_t类型。
ngx_conf_set_bitmask_slot:读取参数的值,并将这些参数的值以bit位的形式存储。例如:HttpDavModule模块的dav_methods指令。

一个模块配置的demo

static ngx_command_t ngx_http_hello_commands[] = {
	{
		ngx_string("hello_string"),
		NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE1,
		ngx_http_hello_string,
		NGX_HTTP_LOC_CONF_OFFSET,
		offsetof(ngx_http_hello_loc_conf_t, hello_string),
		NULL 
	},
	
	ngx_null_command	// 每个模块配置后必不可少的  
						// 它的原型是 #define ngx_null_command  { ngx_null_string, 0, NULL, 0, 0, NULL }
};

我们定义的配置指令,一个叫hello_string可以接收一个或零个参数,可以出现在http server块里面的location配置指令里。该配置的处理函数是ngx_http_hello_string。该配置作用域在NGX_HTTP_LOC_CONF_OFFSET(location中)。该配置信息保存在自定义结构体ngx_http_hello_loc_conf_t 的hello_string字段。

简单模块配置的案例演示

  1. 首先我们在src/core/nginx.c文件中找到ngx_core_commands数组。

  2. 在该数组中添加一条自定义配置。
    在这里插入图片描述

  3. 实现处理函数ngx_conf_my_handler(这个函数名是自己起的)。
    在这里插入图片描述

  4. 重新编译install。

  5. 在nginx.conf配置文件中加上自定义的配置。
    在这里插入图片描述

  6. 测试:./nginx -t
    在这里插入图片描述

模块上下文结构

这是一个ngx_http_module_t类型的静态变量。这个变量实际上是提供一组回调函数指针,这些函数有在创建存储配置信息的对象的函数,也有在创建前和创建后会调用的函数。

ngx_http_module_t结构原型:

typedef struct {
    ngx_int_t   (*preconfiguration)(ngx_conf_t *cf);	// 在创建和读取该模块的配置信息之前被调用。
    ngx_int_t   (*postconfiguration)(ngx_conf_t *cf);	// 在创建和读取该模块的配置信息之后被调用。

    void   *(*create_main_conf)(ngx_conf_t *cf);	/* 调用该函数创建本模块位于http block的配置信息存储结构。
   													该函数成功的时候,返回创建的配置对象。失败的话,返回NULL。*/
    char   *(*init_main_conf)(ngx_conf_t *cf, void *conf);	/* 调用该函数初始化本模块位于http block的配置信息
    存储结构。该函数成功的时候,返回NGX_CONF_OK。失败的话,返回NGX_CONF_ERROR或错误字符串。*/

    void       *(*create_srv_conf)(ngx_conf_t *cf);		/* 调用该函数创建本模块位于http server block的配置信息
    存储结构,每个server block会创建一个。该函数成功的时候,返回创建的配置对象。失败的话,返回NULL。*/
    char       *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);	/* 因为有些配置指令既可以出现在
 					http block,也可以出现在http server block中。
		    那么遇到这种情况,每个server都会有自己存储结构来存储该server的配置,
		    但是在这种情况下http block中的配置与server block中的配置信息发生冲突的时候,就需要调用此函数进行合并,
		    该函数并非必须提供,当预计到绝对不会发生需要合并的情况的时候,就无需提供。当然为了安全起见还是建议提供。
		    该函数执行成功的时候,返回NGX_CONF_OK。失败的话,返回NGX_CONF_ERROR或错误字符串。*/

    void       *(*create_loc_conf)(ngx_conf_t *cf);	/* 调用该函数创建本模块位于location block的配置信息存储结构。
 						每个在配置中指明的location创建一个。该函数执行成功,返回创建的配置对象。失败的话,返回NULL。*/
    char       *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);	/* 与merge_srv_conf类似,这个也是
    进行配置值合并的地方。该函数成功的时候,返回NGX_CONF_OK。失败的话,返回NGX_CONF_ERROR或错误字符串。*/
} ngx_http_module_t;

Nginx里面的配置信息都是上下一层层的嵌套的,对于具体某个location的话,对于同一个配置,如果当前层次没有定义,那
么就使用上层的配置,否则使用当前层次的配置。
这些配置信息一般默认都应该设为一个未初始化的值,针对这个需求,Nginx定义了一系列的宏定义来代表各种配置所对应
数据类型的未初始化值,如下:

#define NGX_CONF_UNSET       -1
#define NGX_CONF_UNSET_UINT  (ngx_uint_t) -1
#define NGX_CONF_UNSET_PTR   (void *) -1
#define NGX_CONF_UNSET_SIZE  (size_t) -1
#define NGX_CONF_UNSET_MSEC  (ngx_msec_t) -1

模块的定义

对于开发一个模块来说,我们都需要定义一个ngx_module_t类型的变量来说明这个模块本身的信息,从某种意义上来说,这是这个模块最重要的一个信息,它告诉了nginx这个模块的一些信息,上面定义的配置信息,还有模块上下文信息,都是通过这个结构来告诉nginx系统的,也就是加载模块的上层代码,都需要通过定义的这个结构,来获取这些信息。

ngx_module_t 原型:

typedef struct ngx_module_s          ngx_module_t;
struct ngx_module_s {
    ngx_uint_t            ctx_index;
    ngx_uint_t            index;

    char                 *name;

    ngx_uint_t            spare0;
    ngx_uint_t            spare1;

    ngx_uint_t            version;
    const char           *signature;

    void                 *ctx;
    ngx_command_t        *commands;
    ngx_uint_t            type;

    ngx_int_t           (*init_master)(ngx_log_t *log);

    ngx_int_t           (*init_module)(ngx_cycle_t *cycle);

    ngx_int_t           (*init_process)(ngx_cycle_t *cycle);
    ngx_int_t           (*init_thread)(ngx_cycle_t *cycle);
    void                (*exit_thread)(ngx_cycle_t *cycle);
    void                (*exit_process)(ngx_cycle_t *cycle);

    void                (*exit_master)(ngx_cycle_t *cycle);

    uintptr_t             spare_hook0;
    uintptr_t             spare_hook1;
    uintptr_t             spare_hook2;
    uintptr_t             spare_hook3;
    uintptr_t             spare_hook4;
    uintptr_t             spare_hook5;
    uintptr_t             spare_hook6;
    uintptr_t             spare_hook7;
};

模块可以提供一些回调函数给nginx,当nginx在创建进程线程或者结束进程线程时进行调用。但大多数模块在这些时刻并不需要做什么,所以都简单赋值为NULL。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1243898.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

安卓开发——Android Studio常见报错与解决方法

1. No toolchains found in the NDK toolchains folder for ABI with prefix: arm-linux-android 这个错误是由于较新版本的NDK的./toolchains目录中没有arm-linux-androideabi文件,解决办法是从旧的NDK版本里面复制到自己的NDK的版本里面,就可以了。 打…

需求调研计划及用户需求调研单

1.目的 2.概述 3.需求调研计划 3.1调研目的 3.2调研范围 3.2.1.调研的职能范围 3.2.2.调研的业务范围 3.2.3.调研的地点范围 3.3调研方式 3.4调研阶段 3.5具体时间安排 软件开发全文档获取:点我获取 1、需求调研计划 2、用户需求调研单 项目名称 客…

【目标检测】保姆级别教程从零开始实现基于Yolov8的一次性筷子计数

前言 一,环境配置 一,虚拟环境创建 二,安装资源包 前言 最近事情比较少,无意间刷到群聊里分享的基于百度飞浆平台的一次性筷子检测,感觉很有意思,恰巧自己最近在学习Yolov8,于是看看能不能复…

Spring配置其他注解Spring注解的解析原理

Spring配置其他注解 Primary注解用于标注相同类型的Bean优先被使用权,Primary是Spring 3.0引入的,与Component和Bean一起使用,标注该Bean的优先级更高,则在通过类型获取Bean或通过Autowired根据类型进行注入时,会选用优…

Mysql数据库 18.Mysql SQL优化

SQL优化 一、插入优化 多条插入语句,影响执行效率 优化方案 1、批量插入: 在一条insert语句中多条数据,但是如果数据量过大,也不能完全使用一条语句语句,建议数据量为一次性插入1000条以下的数据 如果数据量多大&…

【Axure教程】用中继器制作卡片多条件搜索效果

卡片设计通过提供清晰的信息结构、可视化吸引力、易扩展性和强大的交互性,为用户界面设计带来了许多优势,使得用户能够更轻松地浏览、理解和互动。 那今天就教大家如何用中继器制作卡片的模板,以及完成多条件搜索的效果,我们会以…

12个最佳WordPress投票插件

您是否正在为您的网站寻找WordPress投票插件? WordPress投票插件可让您轻松地在您的网站上进行民意调查,用户可以投票。这是在收集见解的同时建立用户参与度的有效策略。 在本文中,我们精心挑选了最好的WordPress投票插件,可帮助…

【Vue】创建第一个实例

步骤&#xff1a; 1.创建容器 2.引包 3.创建实例 4.添加配置项 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body><!--准备容器 --> <di…

ubuntu搭建phpmyadmin+wordpress

Ubuntu搭建phpmyadmin wordpress Linux系统设置&#xff1a;Ubuntu 22配置apache2搭建phpmyadmin配置Nginx环境&#xff0c;搭建wordpress Linux系统设置&#xff1a;Ubuntu 22 配置apache2 安装apache2 sudo apt -y install apache2设置端口号为8080 sudo vim /etc/apache…

VBA经典应用69例:Find方法的应用

《VBA经典应用69例》&#xff08;版权10178981&#xff09;&#xff0c;是我推出的第九套教程&#xff0c;教程是专门针对初级、中级学员在学习VBA过程中可能遇到的案例展开&#xff0c;这套教程案例众多&#xff0c;紧贴“实战”&#xff0c;并做“战术总结”&#xff0c;以便…

旅行商问题(枚举,回溯,动态规划,贪心,分支界限)

文章目录 问题描述暴力枚举回溯法动态规划法贪心法分支界限法 问题描述 假设有一个货郎担要拜访n个城市&#xff0c;他必须选择所要走的路程&#xff0c;路程的限制时每个城市只能拜访一次&#xff0c;而且最后要走到原来出发的城市&#xff0c;要求路径长度。 旅行商问题将要…

C语言第二十五弹--打印菱形

C语言打印菱形 思路&#xff1a;想要打印一个菱形&#xff0c;可以分为上下两部分&#xff0c;通过观察可以发现上半部分星号的规律是 1 3 5 7故理解为 2对应行数 1 &#xff0c;空格是4 3 2 1故理解为 行数-对应行数-1。 上半部分代码如下 for (int i 0;i < line;i){//上…

【C/PTA】函数专项练习(四)

本文结合PTA专项练习带领读者掌握函数&#xff0c;刷题为主注释为辅&#xff0c;在代码中理解思路&#xff0c;其它不做过多叙述。 目录 6-1 计算A[n]1/(1 A[n-1])6-2 递归实现顺序输出整数6-3 自然数的位数(递归版)6-4 分治法求解金块问题6-5 汉诺塔6-6 重复显示字符(递归版)…

git 提交成了LFS格式,如何恢复

平常习惯使用sourceTree提交代码&#xff0c;某次打开时弹出了一个【是否要使用LFS提交】的确认弹窗&#xff0c;当时不知道LFS是什么就点了确认&#xff0c;后续提交时代码全变成了这个样子 因为是初始化的项目首次提交&#xff0c;将近四百个文件全被格式化成了这个样子&…

Python 使用tkinter复刻Windows记事本UI和菜单功能(三)

上一篇&#xff1a;Python 使用tkinter复刻Windows记事本UI和菜单功能&#xff08;二&#xff09;-CSDN博客 下一篇&#xff1a;敬请耐心等待&#xff0c;如发现BUG以及建议&#xff0c;请在评论区发表&#xff0c;谢谢&#xff01; 本文章完成了记事本的新建、保存、另存、打…

为什么 x86 操作系统从 0x7c00 处开始

0x00&#xff1a;x86 架构 BIOS 引导加载程序中的"0x7C00"之谜 你知道 x86 操作系统中的"0x7C00"这个神奇数字吗 ? "0x7C00" 是BIOS加载MBR&#xff08;主引导记录&#xff0c;磁盘中的第一个扇区&#xff09;的内存地址。操作系统或引导加载…

思维模型 等待效应

本系列文章 主要是 分享 思维模型 &#xff0c;涉及各个领域&#xff0c;重在提升认知。越是等待&#xff0c;越是焦虑。 1 等待效应的应用 1.1 等待效应在管理中的应用 西南航空公司是一家美国的航空公司&#xff0c;它在管理中运用了等待效应。西南航空公司鼓励员工在工作中…

XUbuntu22.04之解决gpg keyserver receive failed no data(一百九十三)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

Axios 通过a标签下载文件 跨域下载

<!-- a标签占位 --><a ref"down" ></a>getTest() {this.$axios.request({url: https://cnv13.55.la/download?file_key3695fa9461a0ae59cf3148581e4fe339&handle_typeexcel2pdf,method: get,responseType: blob, // 切记类型 blob}).then(re…

【Java并发】聊聊线程池原理以及实际应用

线程其实对于操作系统来说是宝贵的资源&#xff0c;java层面的线程其实本质还是依赖于操作系统内核的线程进行处理任务&#xff0c;如果频繁的创建、使用、销毁线程&#xff0c;那么势必会非常浪费资源以及性能不高&#xff0c;所以池化技术&#xff08;数据库连接池、线程池&a…