ASP.NET 开发番外体系一:Html与Ashx

前言

Nginx是现阶段最风靡的HTTP
Server之一,根据W3Techs的总结,近来世界排行(按照亚历克斯a)前100万的网站中,Nginx的占有率为6.8%。与Apache相比,Nginx在高并发情况下拥有伟大的属性优势
Nginx属于典型的微内核设计,其基础卓殊不难和古雅,同时持有万分高的可扩充性。Nginx最初只是首要被用于做反向代理,后来随着HTTP主题的成熟和各类HTTP增加模块的增加,Nginx越多被用来顶替Apache而单身负责HTTP
Server的任务,例如方今Tmall内各样部门正进一步多使用Nginx取代Apache,据作者了然,在腾讯和腾讯网等营业所也存在类似情形。
同时,大批量的第三方伸张模块也令Nginx越来越强大。例如,由天猫的工程师清无(王晓哲)和春来(章亦春)所开发的nginx_lua_module可以将Lua语言嵌入到Nginx配置中,从而拔取Lua极大提升了Nginx本身的编程能力,甚至足以不用合作其余脚本语言(如PHP或Python等),只靠Nginx本身就足以兑现复杂工作的拍卖。而春来所开发的ngx_openresty愈来愈通过购并LuaJIT等零件,将Nginx本身变成了一个一心的施用开发平台。方今Tmall数据平台与制品部量子计算的成品都是依照ngx_openresty所开发。对ngxin_lua_module或ngx_openresty感兴趣的爱侣可以参考我在主要词上提交的链接,后续我也可能会写一些与其关于的篇章。
正文将会器重关怀Nginx模块开发入门及基础。近日Nginx的上学材料卓殊少,而增添模块开发相关的材料大概唯有《Emiller’s
Guide To Nginx Module
Development
》一文,此文极度经典,但是出于Nginx版本的形成,其中有数内容可能有点过时。本文是小编在研读那篇小说和Nginx源代码的基础上,对团结上学Nginx模块开发的一个统计。本文将因而一个总体的模块开发实例讲解Nginx模块开发的入门内容。
正文将基于Nginx最新的1.0.0本子,操作系统环境为Linux(Ubuntu10.10)。
Nginx提要
付出Nginx扩张当然紧要前提是对Nginx有早晚的垂询,然则本文并不打算详细演讲Nginx的全体,诸如Nginx的安装和种种详细安顿等内容都得以在Nginx官网的Document中找到,本文在此间只会概括性描述一些末尾可能会用到的规律和定义。
Nginx在Linux下的安装与运作
应用Nginx的第一步是下载Nginx源码包,例如1.0.0的下载地址为http://nginx.org/download/nginx-1.0.0.tar.gz。下载完后用tar命令解压缩,进入目录后安装进度与Linux下一般步骤一样,例如我想将Nginx安装到/usr/local/nginx下,则进行如下命令:

./configure --prefix=/usr/local/nginx
make
make install

安装已毕后可以一直运用上边发号施令启动Nginx:

/usr/local/nginx/sbin/nginx

Nginx默许以Deamon进度启动,输入下列命令:

curl -i http://localhost/

就能够检测Nginx是还是不是曾经打响运行。或者也可以在浏览器中输入http://localhost/,应该能够观望Nginx的迎接页面了。启动后若是想为止Nginx可以行使:

/usr/local/nginx/sbin/nginx -s stop

Nginx配置文件中央构造
布局文件可以看成是Nginx的神魄,Nginx服务在启动时会读入配置文件,而后续大约整个动作表现都是根据布置文件中的指令进行的,因而只要将Nginx本身作为一个处理器,那么Nginx的安排文件可以当做是漫天的次第指令。
上面是一个Nginx配置文件的实例:

#user nobody;
worker_processes 8;
error_log logs/error.log;
pid logs/nginx.pid;
events {
 worker_connections 1024;
}
http {
 include mime.types;
 default_type application/octet-stream;

 sendfile on;
 #tcp_nopush on;
 keepalive_timeout 65;
 #gzip on;

 server {
 listen 80;
 server_name localhost;
 location / {
 root /home/yefeng/www;
 index index.html index.htm;
 }
 #error_page 404 /404.html;
 # redirect server error pages to the static page /50x.html
 #
 error_page 500 502 503 504 /50x.html;
 location = /50x.html {
 root html;
 }
 }
}

Nginx配置文件是纯文本文件,你可以用其他文件编辑器如vim或emacs打开它,日常它会在nginx安装目录的conf下,如本人的nginx安装在/usr/local/nginx,主配置文件默许放在/usr/local/nginx/conf/nginx.conf。
其中“#”表示此行是注释,由于作者为了学习扩充开发安装了一个单纯的Nginx,因此配置文件没有通过太多改动。
Nginx的安顿文件是以block的情势协会的,一个block平日拔取大括号“{}”表示。block分为几个层级,整个配置文件为main层级,那是最大的层级;在main层级下可以有event、http等层级,而http中又会有server
block,server block中得以分包location block。
种种层级可以有谈得来的一声令下(Directive),例如worker_processes是一个main层级指令,它指定Nginx服务的Worker进度数量。有的指令只可以在一个层级中安顿,如worker_processes只好存在于main中,而一些指令可以存在于八个层级,在那种意况下,子block会继承父block的配备,同时假若子block配置了与父block分裂的授命,则会覆盖掉父block的计划。指令的格式是“指令名
参数1 参数2 … 参数N;”,注意参数间可用任意数量空格分隔,最终要加分号。
在付出Nginx
HTTP伸张模块进度中,需求越发注意的是main、server和location八个层级,因为扩大模块平日允许指定新的配备指令在那八个层级中。
说到底要涉及的是陈设文件是足以蕴含的,如上边配置文件中“include
mime.types”就隐含了mine.types那个布局文件,此文件指定了种种HTTP
Content-type。
一般的话,一个server
block表示一个Host,而里面的一个location则意味着一个路由映射规则,这八个block可以说是HTTP配置的主干。
下图是Nginx配置文件一般结构图示。

关于Nginx配置的更加多内容请参见Nginx官方文档。
Nginx模块工作规律概述
(Nginx本身匡助种种模块,如HTTP模块、EVENT模块和MAIL模块,本文只谈谈HTTP模块)
Nginx本身做的劳作实际上很少,当它接受一个HTTP请求时,它只是是通过寻找配置文件将此次请求映射到一个location
block,而此location中所配置的各样指令则会启动不相同的模块去做到工作,因而模块可以当做Nginx真正的分神工小编。经常一个location中的指令会涉及一个handler模块和三个filter模块(当然,两个location可以复用同一个模块)。handler模块负责处理请求,完结响应内容的变型,而filter模块对响应内容展开拍卖。因而Nginx模块开发分为handler开发和filter开发(本文不考虑load-balancer模块)。下图呈现了四回正常请求和响应的进程。

Nginx模块开发实战
上边本文浮现一个简短的Nginx模块开发全经过,大家开发一个叫echo的handler模块,这么些模块作用分外简单,它接受“echo”指令,指令可指定一个字符串参数,模块会输出那个字符串作为HTTP响应。例如,做如下配置:

location /echo {
 echo "hello nginx";
}

则访问http://hostname/echo时会输出hello
nginx。
直观来看,要贯彻那个意义必要三步:1、读入配置文件中echo指令及其参数;2、进行HTTP包装(添加HTTP头等工作);3、将结果回到给客户端。上面本文将分部介绍任何模块的付出进度。
概念模块配置结构
率先大家须求一个社团用于存储从配置文件中读进去的连带指令参数,即模块配置新闻结构。根据Nginx模块开发规则,这几个协会的命名规则为ngx_http_[module-name]_[main|srv|loc]_conf_t。其中main、srv和loc分别用于表示同样模块在三层block中的配置新闻。那里我们的echo模块只须求周转在loc层级下,需求仓储一个字符串参数,因而大家可以定义如下的模块配置:

typedef struct {
 ngx_str_t ed;
} ngx_http_echo_loc_conf_t;

其中字段ed用于存储echo指令指定的急需输出的字符串。注意那里ed的品类,在Nginx模块开发中应用ngx_str_t类型表示字符串,那些类型定义在core/ngx_string中:

typedef struct {
 size_t len;
 u_char *data;
} ngx_str_t;

其中八个字段分别表示字符串的长短和多少先导地址。注目的在于Nginx源代码中对数据类型举行了别称定义,如ngx_int_t为intptr_t的别称,为了保持一致,在支付Nginx模块时也相应使用这一个Nginx源码定义的门类而不要拔取C原生类型。除了ngx_str_t外,其余三个常用的nginx
type分别为:

typedef intptr_t ngx_int_t;
typedef uintptr_t ngx_uint_t;
typedef intptr_t ngx_flag_t;

具体定义请参见core/ngx_config.h。关于intptr_t和uintptr_t请参考C99中的stdint.hhttp://linux.die.net/man/3/intptr\_t
概念指令
一个Nginx模块往往吸收一至多少个指令,echo模块接收一个发令“echo”。Nginx模块使用一个ngx_command_t数组表示模块所能接收的富有模块,其中每一个因素表示一个条指令。ngx_command_t是ngx_command_s的一个又称(Nginx习惯于选拔“_s”后缀命名结构体,然后typedef一个同名“_t”后缀名称作为此结构体的花色名),ngx_command_s定义在
core/ngx_config_file.h中:

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_uint_t offset;
 void *post;
};

中间name是词条指令的称呼,type使用掩码标志位格局布署指令参数,相关可用type定义在core/ngx_config_file.h中:

#define NGX_CONF_NOARGS 0x00000001
#define NGX_CONF_TAKE1 0x00000002
#define NGX_CONF_TAKE2 0x00000004
#define NGX_CONF_TAKE3 0x00000008
#define NGX_CONF_TAKE4 0x00000010
#define NGX_CONF_TAKE5 0x00000020
#define NGX_CONF_TAKE6 0x00000040
#define NGX_CONF_TAKE7 0x00000080
#define NGX_CONF_MAX_ARGS 8
#define NGX_CONF_TAKE12 (NGX_CONF_TAKE1|NGX_CONF_TAKE2)
#define NGX_CONF_TAKE13 (NGX_CONF_TAKE1|NGX_CONF_TAKE3)
#define NGX_CONF_TAKE23 (NGX_CONF_TAKE2|NGX_CONF_TAKE3)
#define NGX_CONF_TAKE123 (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3)
#define NGX_CONF_TAKE1234 (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3 \
 |NGX_CONF_TAKE4)
#define NGX_CONF_ARGS_NUMBER 0x000000ff
#define NGX_CONF_BLOCK 0x00000100
#define NGX_CONF_FLAG 0x00000200
#define NGX_CONF_ANY 0x00000400
#define NGX_CONF_1MORE 0x00000800
#define NGX_CONF_2MORE 0x00001000
#define NGX_CONF_MULTI 0x00002000

其中NGX_CONF_NOARGS代表此命令不接受参数,NGX_CON
F_TAKE1-7代表精确接收1-7个,NGX_CONF_TAKE12意味接受1或2个参数,NGX_CONF_爱谱王表示至少一个参数,NGX_CONF_FLAG表示接受“on|off”……
set是一个函数指针,用于指定一个参数转化函数,那个函数一般是将配备文件中相关指令的参数转化成须要的格式并存入配置结构体。Nginx预定义了有些更换函数,可以方便大家调用,那一个函数定义在core/ngx_conf_file.h中,一般以“_slot”结尾,例如ngx_conf_set_flag_slot将“on或off”转换为“1或0”,再如ngx_conf_set_str_slot将裸字符串转化为ngx_str_t。
conf用于指定Nginx相应布署文件内存其实地址,一般可以透过内置常量指定,如NGX_HTTP_LOC_CONF_OFFSET,offset指定此条指令的参数的偏移量。
上面是echo模块的一声令下定义:

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

指令数组的命名规则为ngx_http_[module-name]_commands,注意数组最终一个要素即使ngx_null_command结束。
参数转化函数的代码为:

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;
 ngx_conf_set_str_slot(cf,cmd,conf);
 return NGX_CONF_OK;
}

本条函数除了调用ngx_conf_set_str_slot转化echo指令的参数外,还将修改了着力模块配置(也就是这些location的布署),将其handler替换为我们编辑的handler:ngx_http_echo_handler。那样就屏蔽了此location的默许handler,使用ngx_http_echo_handler产生HTTP响应。
创设合并配置音信
下一步是概念模块Context。
这里首先须求定义一个ngx_http_module_t类型的结构体变量,命名规则为ngx_http_[module-name]_module_ctx,这几个布局紧要用以定义种种Hook函数。上边是echo模块的context结构:

static ngx_http_module_t ngx_http_echo_module_ctx = {
 NULL, /* preconfiguration */
 NULL, /* postconfiguration */
 NULL, /* create main configuration */
 NULL, /* init main configuration */
 NULL, /* create server configuration */
 NULL, /* merge server configuration */
 ngx_http_echo_create_loc_conf, /* create location configration */
 ngx_http_echo_merge_loc_conf /* merge location configration */
};

可以见到一共有8个Hook注入点,分别会在不相同随时被Nginx调用,由于我们的模块仅仅用于location域,这里将不须求的注入点设为NULL即可。其中create_loc_conf用于初叶化一个计划结构体,如为布局结构体分配内存等工作;merge_loc_conf用于将其父block的配备新闻统一到此结构体中,也就是已毕配置的接续。那三个函数会被Nginx自动调用。注意那里的命名规则:ngx_http_[module-name][create|merge][main|srv|loc]_conf。
下边是echo模块这一个三个函数的代码:

static void *
ngx_http_echo_create_loc_conf(ngx_conf_t *cf)
{
 ngx_http_echo_loc_conf_t *conf;
 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_echo_loc_conf_t));
 if (conf == NULL) {
 return NGX_CONF_ERROR;
 }
 conf->ed.len = 0;
 conf->ed.data = NULL;
 return conf;
}
static char *
ngx_http_echo_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
 ngx_http_echo_loc_conf_t *prev = parent;
 ngx_http_echo_loc_conf_t *conf = child;
 ngx_conf_merge_str_value(conf->ed, prev->ed, "");
 return NGX_CONF_OK;
}

其中ngx_pcalloc用于在Nginx内存池中分红一块空间,是pcalloc的一个包装。使用ngx_pcalloc分配的内存空间不必手工free,Nginx会自行保管,在适度是不是释放。
create_loc_conf新建一个ngx_http_echo_loc_conf_t,分配内存,并初叶化其中的数量,然后再次回到那一个社团的指针;merge_loc_conf将父block域的部署信息统一到create_loc_conf新建的安排结构体中。
其中ngx_conf_merge_str_value不是一个函数,而是一个宏,其定义在core/ngx_conf_file.h中:

#define ngx_conf_merge_str_value(conf, prev, default) \
 if (conf.data == NULL) { \
 if (prev.data) { \
 conf.len = prev.len; \
 conf.data = prev.data; \
 } else { \
 conf.len = sizeof(default) - 1; \
 conf.data = (u_char *) default; \
 } \
 }

还要可以看到,core/ngx_conf_file.h还定义了成百上千merge
value的宏用于merge各样数据。它们的行为相比较相似:使用prev填充conf,假诺prev的数码为空则使用default填充。
编写Handler
下边的劳作是编制handler。handler可以说是模块中真正行事的代码,它最首要有以下四项义务:
读入模块配置。
拍卖作用业务。
产生HTTP header。
产生HTTP body。
下面先贴出echo模块的代码,然后经过分析代码的艺术介绍怎么样完结那四步。这一块的代码比较复杂:

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;
 ngx_http_echo_loc_conf_t *elcf;
 elcf = ngx_http_get_module_loc_conf(r, ngx_http_echo_module);
 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;
 r->headers_out.content_length_n = elcf->ed.len;
 if(r->method == NGX_HTTP_HEAD)
 {
 rc = ngx_http_send_header(r);
 if(rc != NGX_OK)
 {
 return rc;
 }
 }
 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;
 }
 out.buf = b;
 out.next = NULL;
 b->pos = elcf->ed.data;
 b->last = elcf->ed.data + (elcf->ed.len);
 b->memory = 1;
 b->last_buf = 1;
 rc = ngx_http_send_header(r);
 if(rc != NGX_OK)
 {
 return rc;
 }
 return ngx_http_output_filter(r, &out);
}

handler会接收一个ngx_http_request_t指针类型的参数,那些参数指向一个ngx_http_request_t结构体,此结构体存储了这一次HTTP请求的有的音信,这么些布局定义在

http/ngx_http_request.h中:
struct ngx_http_request_s {
 uint32_t signature; /* "HTTP" */
 ngx_connection_t *connection;
 void **ctx;
 void **main_conf;
 void **srv_conf;
 void **loc_conf;
 ngx_http_event_handler_pt read_event_handler;
 ngx_http_event_handler_pt write_event_handler;
#if (NGX_HTTP_CACHE)
 ngx_http_cache_t *cache;
#endif
 ngx_http_upstream_t *upstream;
 ngx_array_t *upstream_states;
 /* of ngx_http_upstream_state_t */
 ngx_pool_t *pool;
 ngx_buf_t *header_in;
 ngx_http_headers_in_t headers_in;
 ngx_http_headers_out_t headers_out;
 ngx_http_request_body_t *request_body;
 time_t lingering_time;
 time_t start_sec;
 ngx_msec_t start_msec;
 ngx_uint_t method;
 ngx_uint_t http_version;
 ngx_str_t request_line;
 ngx_str_t uri;
 ngx_str_t args;
 ngx_str_t exten;
 ngx_str_t unparsed_uri;
 ngx_str_t method_name;
 ngx_str_t http_protocol;
 ngx_chain_t *out;
 ngx_http_request_t *main;
 ngx_http_request_t *parent;
 ngx_http_postponed_request_t *postponed;
 ngx_http_post_subrequest_t *post_subrequest;
 ngx_http_posted_request_t *posted_requests;
 ngx_http_virtual_names_t *virtual_names;
 ngx_int_t phase_handler;
 ngx_http_handler_pt content_handler;
 ngx_uint_t access_code;
 ngx_http_variable_value_t *variables;
 /* ... */
}

由于ngx_http_request_s定义相比长,那里我只截取了一有的。能够见见其中有诸如uri,args和request_body等HTTP常用消息。那里须求越发注意的多少个字段是headers_in、headers_out和chain,它们各自表示request
header、response header和输出数据缓冲区链表(缓冲区链表是Nginx
I/O中的紧要内容,前边会独自介绍)。
第一步是获得模块配置信息,这一块只要简单利用ngx_http_get_module_loc_conf就足以了。
其次步是效果逻辑,因为echo模块极度简单,只是简单输出一个字符串,所以那边没有效应逻辑代码。
其三步是安装response
header。Header内容可以通过填写headers_out落实,大家那边只设置了Content-type和Content-length等基本内容,ngx_http_headers_out_t定义了有着可以安装的HTTP
Response Header新闻:

typedef struct {
 ngx_list_t headers;
 ngx_uint_t status;
 ngx_str_t status_line;
 ngx_table_elt_t *server;
 ngx_table_elt_t *date;
 ngx_table_elt_t *content_length;
 ngx_table_elt_t *content_encoding;
 ngx_table_elt_t *location;
 ngx_table_elt_t *refresh;
 ngx_table_elt_t *last_modified;
 ngx_table_elt_t *content_range;
 ngx_table_elt_t *accept_ranges;
 ngx_table_elt_t *www_authenticate;
 ngx_table_elt_t *expires;
 ngx_table_elt_t *etag;
 ngx_str_t *override_charset;
 size_t content_type_len;
 ngx_str_t content_type;
 ngx_str_t charset;
 u_char *content_type_lowcase;
 ngx_uint_t content_type_hash;
 ngx_array_t cache_control;
 off_t content_length_n;
 time_t date_time;
 time_t last_modified_time;
} ngx_http_headers_out_t;

此间并不带有所有HTTP头新闻,若是必要可以动用agentzh(春来)开发的Nginx模块HttpHeadersMore在指令中指定越来越多的Header头音信。
设置好头音讯后拔取ngx_http_send_header就可以将头新闻输出,ngx_http_send_header接受一个ngx_http_request_t类型的参数。
第四步也是最重点的一步是输出Response
body。这里首先要领会Nginx的I/O机制,Nginx允许handler四遍暴发一组输出,可以生出很多次,Nginx将出口协会成一个单链表结构,链表中的每个节点是一个chain_t,定义在core/ngx_buf.h:

struct ngx_chain_s {
 ngx_buf_t *buf;
 ngx_chain_t *next;
};

其中ngx_chain_t是ngx_chain_s的别名,buf为某个数据缓冲区的指针,next指向下一个链表节点,可以见见那是一个极度简单的链表。ngx_buf_t的概念相比长同时很复杂,那里就不贴出来了,请自行参考core/ngx_buf.h。ngx_but_t中相比较紧要的是pos和last,分别代表要缓冲区数据在内存中的开场面址和最后地址,这里大家将配置中字符串传进去,last_buf是一个位域,设为1意味着此缓冲区是链表中最后一个因素,为0表示前面还有元素。因为大家唯有一组数据,所以缓冲区链表中只有一个节点,假如需要输入多组数据可将各组数据放入分裂缓冲区后插入到链表。下图展现了Nginx缓冲链表的结构:

缓冲数据准备好后,用ngx_http_output_filter就足以出口了(会送到filter举行种种过滤处理)。ngx_http_output_filter的率先个参数为ngx_http_request_t结构,第一个为出口链表的发端地址&out。ngx_http_out_put_filter会遍历链表,输出所有数据。
上述就是handler的兼具工作,请对照描述了然位置贴出的handler代码。
组合Nginx Module
地点已毕了Nginx模块各类零部件的花费上边就是将那一个构成起来了。一个Nginx模块被定义为一个ngx_module_t结构,那个布局的字段很多,不过初始和最后若干字段一般可以透过Nginx内置的宏去填充,上面是咱们echo模块的模块主体定义:

ngx_module_t ngx_http_echo_module = {
 NGX_MODULE_V1,
 &ngx_http_echo_module_ctx, /* module context */
 ngx_http_echo_commands, /* module directives */
 NGX_HTTP_MODULE, /* module type */
 NULL, /* init master */
 NULL, /* init module */
 NULL, /* init process */
 NULL, /* init thread */
 NULL, /* exit thread */
 NULL, /* exit process */
 NULL, /* exit master */
 NGX_MODULE_V1_PADDING
};

千帆竞发和尾声分别用NGX_MODULE_V1和NGX_MODULE_V1_PADDING
填充了好多字段,就不去探索了。那里关键必要填写的新闻从上到下以一一为context、指令数组、模块类型以及若干特定事件的回调处理函数(不必要能够置为NULL),其中内容如故相比较好精通的,注意大家的echo是一个HTTP模块,所以那边类型是NGX_HTTP_MODULE,其余可用类型还有NGX_EVENT_MODULE(事件处理模块)和NGX_MAIL_MODULE(邮件模块)。
如此,整个echo模块就写好了,上边给出echo模块的完整代码:

/*
* Copyright (C) Eric Zhang
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
/* Module config */
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);
static void *ngx_http_echo_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_echo_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child);
/* Directives */
static ngx_command_t ngx_http_echo_commands[] = {
 { ngx_string("echo"),
 NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
 ngx_http_echo,
 NGX_HTTP_LOC_CONF_OFFSET,
 offsetof(ngx_http_echo_loc_conf_t, ed),
 NULL },
 ngx_null_command
};
/* Http context of the module */
static ngx_http_module_t ngx_http_echo_module_ctx = {
 NULL, /* preconfiguration */
 NULL, /* postconfiguration */
 NULL, /* create main configuration */
 NULL, /* init main configuration */
 NULL, /* create server configuration */
 NULL, /* merge server configuration */
 ngx_http_echo_create_loc_conf, /* create location configration */
 ngx_http_echo_merge_loc_conf /* merge location configration */
};
/* Module */
ngx_module_t ngx_http_echo_module = {
 NGX_MODULE_V1,
 &ngx_http_echo_module_ctx, /* module context */
 ngx_http_echo_commands, /* module directives */
 NGX_HTTP_MODULE, /* module type */
 NULL, /* init master */
 NULL, /* init module */
 NULL, /* init process */
 NULL, /* init thread */
 NULL, /* exit thread */
 NULL, /* exit process */
 NULL, /* exit master */
 NGX_MODULE_V1_PADDING
};
/* Handler function */
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;
 ngx_http_echo_loc_conf_t *elcf;
 elcf = ngx_http_get_module_loc_conf(r, ngx_http_echo_module);
 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;
 r->headers_out.content_length_n = elcf->ed.len;
 if(r->method == NGX_HTTP_HEAD)
 {
 rc = ngx_http_send_header(r);
 if(rc != NGX_OK)
 {
 return rc;
 }
 }
 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;
 }
 out.buf = b;
 out.next = NULL;
 b->pos = elcf->ed.data;
 b->last = elcf->ed.data + (elcf->ed.len);
 b->memory = 1;
 b->last_buf = 1;
 rc = ngx_http_send_header(r);
 if(rc != NGX_OK)
 {
 return rc;
 }
 return ngx_http_output_filter(r, &out);
}
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;
 ngx_conf_set_str_slot(cf,cmd,conf);
 return NGX_CONF_OK;
}
static void *
ngx_http_echo_create_loc_conf(ngx_conf_t *cf)
{
 ngx_http_echo_loc_conf_t *conf;
 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_echo_loc_conf_t));
 if (conf == NULL) {
 return NGX_CONF_ERROR;
 }
 conf->ed.len = 0;
 conf->ed.data = NULL;
 return conf;
}
static char *
ngx_http_echo_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
 ngx_http_echo_loc_conf_t *prev = parent;
 ngx_http_echo_loc_conf_t *conf = child;
 ngx_conf_merge_str_value(conf->ed, prev->ed, "");
 return NGX_CONF_OK;
}

Nginx模块的设置
Nginx不帮忙动态链接模块,所以安装模块须求将模块代码与Nginx源代码进行双重编译。安装模块的步骤如下:
1、编写模块config文件,这么些文件必要放在和模块源代码文件放在同样目录下。文件内容如下:

ngx_addon_name=模块完整名称
HTTP_MODULES="$HTTP_MODULES 模块完整名称"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/源代码文件名"

2、进入Nginx源代码,使用上边发号施令编译安装
./configure –prefix=安装目录 –add-module=模块源代码文件目录

make
make install

如此那般就落成安装了,例如,我的源代码文件放在/home/yefeng/ngxdev/ngx_http_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"

编译安装命令为:

./configure --prefix=/usr/local/nginx --add-module=/home/yefeng/ngxdev/ngx_http_echo
make
sudo make install

诸如此类echo模块就被装置在我的Nginx上了,下边测试一下,修改配置文件,增添以下一项配置:

location /echo {
 echo "This is my first nginx module!!!";
}

然后用curl测试一下:

curl -i http://localhost/echo

结果如下:

能够看看模块已经司空见惯办事了,也得以在浏览器中打开网址,就可以见到结果:

更深远的上学
本文只是不难介绍了Nginx模块的开销进度,由于篇幅的原由,不可能左右逢原。因为近年来Nginx的求学材料很少,假如读者愿意更深远学习Nginx的原理及模块开发,那么阅读源代码是最好的艺术。在Nginx源代码的core/下放有Nginx的主导代码,对通晓Nginx的内部工作机制极度有赞助,http/目录下有Nginx
HTTP相关的已毕,http/module下放有大批量停放http模块,可供读者读书模块的付出,别的在http://wiki.nginx.org/3rdPartyModules上有多量绝妙的第三方模块,也是老大好的读书材料。
如有意见提出或难点欢迎发送邮件至ericzhang.buaa@gmail.com。希望本文对您抱有支持!!!
参考文献
[1] Evan Miller, Emiller’s Guide To Nginx Module Development.
http://www.evanmiller.org/nginx-modules-guide.html,
2009
[2]
http://wiki.nginx.org/Configuration
[3] Clément Nedelcu, Nginx Http Server. Packt Publishing, 2010

分享自:
codinglabs

浏览器发送网址->IIS接收->分给绑定域名的网站->网站依照后缀调用isapi.dll来处理。

下一场数据是怎么发送到服务器的,具体经过可以看:Web开发,浏览器通讯原理及流程那一点事,你应当听说下

 

自打微软出了MVC,才校正了这一证实,原来创制的ASP.NET网站,被改名换姓为ASP.NET
Web Forms网站。

 图片 1

而指定某种后缀用哪类dll去处理的进程,IIS上叫处理程序映射

 

 

OK,上边的历程简化就是说:

IIS收到有一个伸手后,依照商事,分解字符串,解析出种参数。

一:若是没有ASP.NET、JSP、PHP等后台语言,网页是哪些的? 

为此,即使你想用asp.net统一管理没有后缀,或随便乱取的后缀,就需求添加叫通用映射(就是*.*)到aspnet_isapi.dll去。

第一是网址对应的Host,按照Host丢给IIS上相应绑定域名的站点去处理。

1:当你在浏览器输入:http://www.cyqdata.com
的时候,那时候,浏览器会基于Http协议,按协议组装成相应的数量,然后发往指定的服务器。

2:你服务器上有个IIS,正在监听着(默许)80端口。

图片 2 

图片 3 

到这边,ASP.NET平台就到位了,剩下的主是基于那两接口,写不一样的插件,类似于插件开发。

此后的宣传,直接把WebForm站点,就叫ASP.NET网站(从VS成立网站项目上的名目就能够看出来),那几个插件就成了ASP.NET的表示。 

然后对应的站点收到转来的央浼后,初叶分析网址的后缀,因为分裂的网址,决定着分化的ISAPI筛选程序处理过。

然后aspnet_isapi经过各个流程及初步化对象,最后留下了五个最基础接口:

对应于ASP.NET就是aspnet_isapi.dll 

1:

当然,首个插件,就是Web
Forms插件了,并且默认集成进去了,之后就是WebForms插件的世界了。

再然后,数据千新万哭的流传你服务器来了。

IHttpModule和IHttpHandle

比如*.aspx、*.ashx等.net相关的后缀默许就映射到aspnet_isapi.dll。 

席卷最初VS IDE环境创建网站时,都把那几个WebForm站点称为