nginx的http模块开发(直接发送html文件方式)

14 篇文章 0 订阅
10 篇文章 0 订阅

自己写的一个简单返回html文件的模块,但是返回不成功,需要学习一下filter模块的工作细节才能知道原因。
不多说,放代码
ngx_http_echo_module.c


/*
    zhuheming 20160811
*/

#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>

static ngx_int_t
ngx_http_echo_handler(ngx_http_request_t *r);

typedef struct{
    ngx_str_t ed;   
}ngx_http_echo_loc_conf_t;

static char *
ngx_http_echo(ngx_conf_t *cf,ngx_command_t *cmd,void *conf)
{
    ngx_http_core_loc_conf_t *clcf;
    clcf=ngx_http_conf_get_module_loc_conf(cf,ngx_http_core_module);
    clcf->handler=ngx_http_echo_handler;

    return NGX_CONF_OK;
}

static ngx_command_t ngx_http_echo_commands[]={
    {ngx_string("echo"),
     NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
     ngx_http_echo,
     NGX_HTTP_LOC_CONF_OFFSET,
     offsetof(ngx_http_echo_loc_conf_t,ed),
     NULL
    },
    ngx_null_command
};

static ngx_http_module_t ngx_http_echo_module_ctx ={
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL
};

ngx_module_t ngx_http_echo_module = {
    NGX_MODULE_V1,
    &ngx_http_echo_module_ctx,
    ngx_http_echo_commands,
    NGX_HTTP_MODULE,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NGX_MODULE_V1_PADDING
};


static ngx_int_t
ngx_http_echo_handler(ngx_http_request_t *r)
{
    ngx_int_t rc;
    ngx_buf_t *b;
    ngx_chain_t out;

    if(!(r->method & (NGX_HTTP_HEAD|NGX_HTTP_GET|NGX_HTTP_POST)))
    {
        return NGX_HTTP_NOT_ALLOWED;
    }
 //设置报文头
    r->headers_out.content_type.len = sizeof("text/html") - 1;
    r->headers_out.content_type.data = (u_char *) "text/html";

    r->headers_out.status = NGX_HTTP_OK;

    if(r->method == NGX_HTTP_HEAD)
    {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "send head method to client!");
        rc = ngx_http_send_header(r);
        if(rc != NGX_OK)
        {
            return rc;
        }
    }
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "send not head method to client!");
    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
    if(b == NULL)
    {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate response buffer.");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

//直接指定文件位置,后续可以加入到配置文件中
   u_char *filename=(u_char *)"html/echotest.html";
    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "send %s to client!",filename);

    out.buf = b;
    out.next = NULL;

//设置buf的方式为file方式,设置文件句柄,文件名
    b->in_file=1;
    b->file=ngx_pcalloc(r->pool,sizeof(ngx_file_t));
    b->file->fd=ngx_open_file(filename,NGX_FILE_RDONLY,NGX_FILE_OPEN,0);
    b->file->name.data=filename;
    b->file->name.len=strlen(filename);
    b->file->log=r->connection->log;
    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "send file fd : %d!",b->file->fd);
    if(b->file->fd<0){
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "open file error!");
        return NGX_HTTP_NOT_FOUND;
    }
    if(ngx_file_info(filename,&b->file->info)==NGX_FILE_ERROR){
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "get file info error!");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;  
    }
    //设置文件开始读取和结束位置
    b->file_pos=0;
    b->file_last=b->file->info.st_size;
    //加入到文件句柄清除
    if(b->file->fd!=NGX_INVALID_FILE){
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "add file to pool_cleanup!");
        ngx_pool_cleanup_t *cln=ngx_pool_cleanup_add(r->pool,sizeof(ngx_pool_cleanup_t));
        cln->handler=ngx_pool_cleanup_file;

        ngx_pool_cleanup_file_t *clnf=cln->data;
        clnf->fd=b->file->fd;
        clnf->name=b->file->name.data;
        clnf->log=r->pool->log;
    }

    r->headers_out.content_length_n=b->file->info.st_size;
    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "send http is file : %1d!",b->in_file);
    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "send http file name : %s!",b->file->name.data);
    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "send http file_last : %d!",b->file_last);
    rc = ngx_http_send_header(r);
    if(rc != NGX_OK)
    {
        return rc;
    }

    //设置最后一个chain标志,还少一个b->lastbuf=1
    //这样nginx认为没有读取完成,不会发送报文体
    b->last_in_chain=1;


    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "send http outputfilter !");
    return ngx_http_output_filter(r, &out);
}

nginx.conf里是这样加的
location /echo {
echo ;
}
只有命令,没有用到参数,也不用解析参数

另外就是增加一个config文件,内容如下

ngx_addon_name=ngx_http_echo_module
HTTP_MODULES="$HTTP_MODULES ngx_http_echo_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_echo_module.c"

ngx_addon_name是模块名称
HTTP_MODULES是所有http模块,所以在后面添加一个新模块
NGX_ADDON_SRCS是新增模块的源代码,$ngx_addon_dir值取自configure中的参数
文件放在和源代码同一个目录下

这几块添加之后,就可以开始执行configure命令了
添加模块之后需要增加参数

–add-module=PATH PATH是新增模块config和源代码存放的目录

执行之后nginx会生成一些makefile文件,ngx_modules.c文件之类的,里面就已经将这个模块包含在内了


后来经过跟踪,发现ngx_http_write_filter_module.c中的ngx_http_write_filter函数中cl->buf->last_buf为0,就是说在ngx_http_echo_module.c中,需要加一个b->lastbuf=1,来表示这是最后一块buf。现在已经成功收到。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
nginx是一个高性能的Web服务器,同时也是一个反向代理服务器和电子邮件(IMAP/POP3)代理服务器。它最显著的特点是具有高并发处理能力和低内存占用。为了满足不同用户的需求,nginx提供了模块化的架构,可以通过开发模块来扩展其功能。 深入理解nginx模块开发,首先需要了解nginx的架构。nginx的主要部分包括master进程和worker进程。master进程负责管理worker进程,而worker进程负责处理实际的客户端请求nginx模块系统允许开发者向master进程或worker进程添加自定义的功能。 在nginx模块开发中,主要涉及到以下几个方面的内容: 1. 配置文件解析:nginx的配置文件是使用类似于C语言的语法进行解析的。模块开发者需要了解nginx的配置文件语法,并且能够解析和处理自定义的配置项。 2. HTTP请求处理:开发基于HTTP协议的模块时,需要能够处理和解析HTTP请求模块可以拦截特定的URL,处理请求,并返回相应的响应。 3. 事件处理:nginx使用事件驱动的模型来处理并发请求模块开发者需要了解事件驱动的机制,实现自己的事件处理逻辑,并与nginx的事件处理系统进行交互。 4. 内存管理:nginx以低内存占用著称,这是因为它使用了自己的内存管理机制。模块开发者需要了解nginx的内存管理方式,并遵循相应的规则。 5. 日志记录:nginx提供了灵活的日志记录功能。模块开发者可以通过定制日志记录方式,将特定的信息记录到指定的日志文件中。 总的来说,深入理解nginx模块开发与架构解析需要对nginx的整体架构有深入了解,并具备一定的系统编程和网络编程经验。通过开发和调试模块,可以进一步理解nginx的原理和内部实现,掌握更多高性能Web服务器开发的知识和技巧。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值