Nginx模块开发(1)————类helloworld
来源:互联网 发布:手机淘宝怎么查号截图 编辑:程序博客网 时间:2024/06/06 21:43
Nginx看了一点了,准备写个helloworld试试,觉得只看书的话很多东西都乱乱的,晕晕的,印象不深。
我的helloworld模块的目的就是:能够在浏览器里输入http://你的ip地址/lcwtest时,能够显示Hello my name is Lin Chuangwei!
为此,需要写两个文件,一个模块的源文件,一个模块的配置文件,还要改另外一个文件,就是nginx的配置文件
下面先看模块的源文件:(注释我写的超级详细的)
ngx_http_lcwtest_module.c
//start from the very beginning,and to create greatness//@author: Chuangwei Lin//@E-mail:979951191@qq.com//@brief: 一个简单的nginx的HTTP模块#include <ngx_config.h>//包含必要的头文件#include <ngx_core.h>#include <ngx_http.h>//先声明函数static char *ngx_http_lcwtest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);static ngx_int_t ngx_http_lcwtest_handler(ngx_http_request_t *r);//ngx_command_t定义模块的配置文件参数static ngx_command_t ngx_http_lcwtest_commands[] ={ { //配置项名称 ngx_string("lcwtest"), //配置项类型,将指定配置项可以出现的位置 //例如出现在server{}或location{}中,以及他可以携带的参数个数 NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LMT_CONF | NGX_CONF_NOARGS, //ngx_command_t结构体中的set成员, //当在某个配置块中出现lcwtest配置项时,Nginx将会调用ngx_http_lcwtest方法 //ngx_http_lcwtest方法将在下面实现 ngx_http_lcwtest, //在配置文件中的偏移量conf NGX_HTTP_LOC_CONF_OFFSET, //offset通常用于使用预设的解析方法解析配置项,需要与conf配合使用 0, //配置项读取后的处理方法,必须是ngx_conf_post_t结构的指针 NULL }, //ngx_null_command是一个空的ngx_command_t结构,用来表示数组的结尾 ngx_null_command};//ngx_http_module_t的8个回调方法,因为目前没有什么工作是必须在HTTP框架初始化//时完成的,所以暂时不必实现ngx_http_module_t的8个回调方法static ngx_http_module_t ngx_http_lcwtest_module_ctx ={ NULL, // preconfiguration解析配置文件前调用 NULL, // postconfiguration 完成配置文件解析后调用 NULL, // create main configuration当需要创建数据结构用于存储main级别的 //(直属于http{}块的配置项)的全局配置项时 NULL, // init main configuration常用于初始化main级别的配置项 NULL, // create server configuration当需要创建数据结构用于存储srv级别的 //(直属于server{}块的配置项)的配置项时 NULL, // merge server configuration用于合并main级别和srv级别下的同名配置项 NULL, // create location configuration 当需要创建数据结构用于存储loc级别的 //(直属于location{}块的配置项)的配置项时 NULL // merge location configuration 用于合并srv和loc级别下的同名配置项};//定义lcwtest模块//lcwtest模块在编译时会被加入到ngx_modules全局数组中//Nginx在启动时,会调用所有模块的初始化回调方法//HTTP框架初始化时会调用ngx_http_module_t中的8个方法//HTTP模块数据结构ngx_module_t ngx_http_lcwtest_module ={ NGX_MODULE_V1,//该宏为下面的ctx_index,index,spare0,spare1,spare2,spare3,version变量 //提供了初始化的值:0,0,0,0,0,0,1 //ctx_index表示当前模块在这类模块中的序号 //index表示当前模块在所有模块中的序号,Nginx启动时会根据ngx_modules数组设置各模块的index值 //spare0 spare系列的保留变量,暂未使用 //spare1 //spare2 //spare3 //version模块的版本,便于将来的扩展,目前只有一种,默认为1 &ngx_http_lcwtest_module_ctx, //ctx用于指向一类模块的上下文结构 ngx_http_lcwtest_commands, //commands将处理nginx.conf中的配置项 NGX_HTTP_MODULE, //模块的类型,与ctx指针紧密相关,取值范围是以下5种: //NGX_HTTP_MODULE,NGX_CORE_MODULE,NGX_CONF_MODULE,NGX_EVENT_MODULE,NGX_MAIL_MODULE //以下7个函数指针表示有7个执行点会分别调用这7种方法,对于任一个方法而言,如果不需要nginx在某个是可执行它 //那么简单地将他设为空指针即可 NULL, //master进程启动时回调init_master NULL, //init_module回调方法在初始化所有模块时被调用,在master/worker模式下, //这个阶段将在启动worker子进程前完成 NULL, //init_process回调方法在正常服务前被调用,在master/worker模式下, //多个worker子进程已经产生,在每个worker子进程的初始化过程会调用所有模块的init_process函数 NULL, //由于nginx暂不支持多线程模式,所以init thread在框架代码中没有被调用过 NULL, // exit thread,也不支持 NULL, //exit process回调方法将在服务停止前调用,在master/worker模式下,worker进程会在退出前调用它 NULL, //exit master回调方法将在master进程退出前被调用 NGX_MODULE_V1_PADDING //这里是8个spare_hook变量,是保留字段,目前没有使用,Nginx提供了NGX_MODULE_V1_PADDING宏来填充};/******************************************************函数名:ngx_http_lcwtest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)参数:功能:lcwtest方法的实现*******************************************************/static char* ngx_http_lcwtest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf){ ngx_http_core_loc_conf_t *clcf; //首先找到lcwtest配置项所属的配置块,clcf貌似是location块内的数据 //结构,其实不然,它可以是main、srv或者loc级别配置项,也就是说在每个 //http{}和server{}内也都有一个ngx_http_core_loc_conf_t结构体 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); //http框架在处理用户请求进行到NGX_HTTP_CONTENT_PHASE阶段时,如果 //请求的主机域名、URI与lcwtest配置项所在的配置块相匹配,就将调用我们 //实现的ngx_http_lcwtest_handler方法处理这个请求 //ngx_http_lcwtest_handler将在下面实现 clcf->handler = ngx_http_lcwtest_handler; return NGX_CONF_OK;}/******************************************************函数名:ngx_http_lcwtest_handler(ngx_http_request_t *r)参数:ngx_http_request_t结构体功能:ngx_http_lcwtest_handler方法的实现*******************************************************/static ngx_int_t ngx_http_lcwtest_handler(ngx_http_request_t *r){ //必须是GET或者HEAD方法,否则返回405 Not Allowed if (!(r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD))) { return NGX_HTTP_NOT_ALLOWED; } //丢弃请求中的包体 ngx_int_t rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } //设置返回的Content-Type。注意,ngx_str_t有一个很方便的初始化宏 //ngx_string,它可以把ngx_str_t的data和len成员都设置好 ngx_str_t type = ngx_string("text/plain"); //返回的包体内容 ngx_str_t response = ngx_string("Hello my name is Lin Chuangwei!"); //只要指定headers_out中的成员,就可以在调用ngx_http_send_header时正确的把HTTP头部发出 //设置返回状态码 r->headers_out.status = NGX_HTTP_OK; //响应包是有包体内容的,所以需要设置Content-Length长度 r->headers_out.content_length_n = response.len; //设置Content-Type r->headers_out.content_type = type; //发送http头部 rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } //构造ngx_buf_t结构准备发送包体 ngx_buf_t *b; //开辟ngx_buf_t的内存空间 b = ngx_create_temp_buf(r->pool, response.len); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } //将Hello my name is Lin Chuangwei!拷贝到ngx_buf_t指向的内存中 ngx_memcpy(b->pos, response.data, response.len); //注意,一定要设置好last指针,如果b->last和b->pos相等,那么HTTP框架是不会发送一个字节的包体的 b->last = b->pos + response.len; //声明这是最后一块缓冲区 b->last_buf = 1; //构造发送时的ngx_chain_t结构体 ngx_chain_t out; //赋值ngx_buf_t out.buf = b; //设置next为NULL out.next = NULL; //最后一步发送包体,http框架会调用ngx_http_finalize_request方法结束请求 return ngx_http_output_filter(r, &out);}
下面是配置文件:
ngx_addon_name=ngx_http_lcwtest_moduleHTTP_MODULES="$HTTP_MODULES ngx_http_lcwtest_module"NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_lcwtest_module.c"
之前我写过注释在里面,不过后来编译出错了我就把注释删了,有注释的如下 #配置文件#ngx_addon_name仅在configure执行时使用一般设置为模块名称#保存所有的HTTP模块名称,每个HTTP模块间由空格符相连,再重新设置HTTP_MODULES#时,不要直接覆盖它,因为configure调用到自定义的config脚本前,已经将各个HTTP#模块设置到HTTP_MODULES中了,因此,要像下面这样设置#NGX_ADDON_SRCS用于指定新增模块的源代码,多个待编译的源代码间以空格符相连#在设置HTTP_MODULES可以使用$ngx_addon_dir变量,它等价于configure执行时#--add-module=PATH的PATH参数
我新建了一个文件夹lcw_nginx,路径要记一下,等下会用到,配置的时候会用到。里面就放两个文件:ngx_http_lcwtest_module.c和config
好了,接下来可以开始编译Nginx了,到之前解压nginx的那个目录下运行以下指令
./configure –add-module=刚才新建文件的那个路径(比如我那个lcw_nginx的文件夹路径是/mnt/hgfs/lcwprogram/lcw_nginx)
配置好了之后,运行make,之后等待编译完成
接下来修改nginx的配置文件,我的配置文件是默认的路径:/usr/local/nginx/conf,打开该文件夹下面的nginx.conf
直接在
http {
……
server {
……..
location / {
root html;
index index.php index.html index.htm;
}
location /lcwtest {
lcwtest;
}
}
}
块中添加该块
location /lcwtest {
lcwtest;
}
保存之后就可以了。
之后,因为我之前安装过nginx,默认的路径是/usr/local/nginx/sbin/所以我去运行了那下面的nginx,结果出错了,错误显示如下
按照这个显示应该是我那个命令没有被编进nginx里面,但是明明我都编译过了啊。原来是这样:我们现在编译的那个nginx并没有被更新到那个文件夹下面,这其实是另一个问题:就是安装成功的nginx如何添加为编译安装的模块,我们可以按照上面的步骤进行编译,但在最后,别忘记了一个步骤:替换nginx的二进制文件
我们新编译好的nginx在开始下载nginx源码然后解压的文件目录下,objs/nginx 而安装后的默认是在/usr/local/nginx/sbin下,我们将它cp过去替换就好了,最好将原来的备份下,免得出错了没有办法还原回来。
最后启动,或者reload都可以,然后在浏览器中输入http://ip地址/lcwtest ,就会出现下面的页面啦
我是在虚拟机上搭建的nginx,然后在windows10下面的360极速浏览器访问的,有些人可能会访问不成功,你试下,直接输入http://ip地址看看会不会显示默认的页面,如果没有,很有可能就是虚拟机的80端口被防火墙屏蔽了,要先开启才可以。
另外,nginx -t命令可以帮你当你看看配置文件的语法等等,执行后 nginx会去测试你得配置文件的语法,并告诉你配置文件是否写得正确,同时也告诉了你配置文件得路径:
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
- Nginx模块开发(1)————类helloworld
- 开发Nginx模块Helloworld
- nginx 源码学习笔记(一)——初识nginx helloworld模块
- nginx 源码学习笔记(一)——初识nginx helloworld模块
- nginx 源码学习笔记(一)——初识nginx helloworld模块
- nginx开发学习——过滤模块
- Nginx模块开发—数组模型
- Nginx模块开发—队列模型
- Nginx模块开发 —进程模型
- Nginx模块开发(5)————开发简单的HTTP过滤模块
- Nginx模块开发(15)—日志模型
- Nginx 模块开发(1)—— 一个稍稍能说明问题模块开发 Step By Step 过程
- nginx开发学习——handler模块(一)
- nginx开发学习——handler模块(二)
- nginx模块开发—HTTP初始化之listen
- Nginx模块开发(2)————下载文件
- Nginx模块开发(3)————使用upstream访问第三方服务
- Nginx模块开发(4)————使用subrequest访问第三方服务
- Elastos自动下载、更新源码工具--DownloadCode.sh
- 具有动态效果的响应式设计
- calligraphy(高效加载字体包)使用方法
- Android Studio 使用总结
- java中instanceof的用法
- Nginx模块开发(1)————类helloworld
- 小记个人认为的java各概念的举例理解
- CSS3给页面打标签
- Phoenix 连接hbase 异常:Caused by: java.lang.ClassNotFoundException: org.iq80.snappy.CorruptionException
- Android自定义流式布局-FlowLayout
- 坚持做这20件小事,让你的人生大不同!
- iOS设计模式——单例模式,你看我就够了.两行代码创建单例(兼容ARC/MRC)
- 在代码中使用Autolayout (1) – 按比例缩放和优先级
- js 点击按钮跳转 window.location.href