缘由
今天阅读 深入理解nginx 的第五章,前半部分讲解了upstream的问题,并且指导完成了一个例子。
upstream
先来回答upstream拿来做什么:客户端请求nginx,nginx将请求转发给第三方服务器(也称上游服务器),第三方服务器返回响应,nginx将响应转发给客户端。这时,nginx作为了一个代理服务器。一般,我们只是把第三方服务器的内容原封不动的返回给客户端。这样做的目的主要是减轻上游服务器端的压力。
例子
背景描述
我们要利用nginx的upstream完成这样一个功能,当然我们访问“http://localhost/test?word”的时候,nginx会把word这个单词(可以是任意单词),传递归google,那么google就用这个word完成搜索,然后将搜索后的页面返回给nginx,nginx再返回给我们。这个例子基本就说清楚了为什么在国内用反向代码就可以访问。思路总览
那么下面,我按照我的思路来为大家理一下,当然我的思路肯定是比不上书上清晰,代码写的也没有书上工整。首先看我们使用到了那些结构体和方法。下面一幅截图看清楚了,我使用的所有的结构体和方法。作为一个单独的模块
由于我们写的是一个独立的模块,所以肯定要按照nginx的要求完成ngx_module_t 这个结构体:这是对于所有模块都需要有的ngx_module_t,书中87页有描述:
ngx_module_t ngx_http_mytest_module =
{
NGX_MODULE_V1,
&ngx_http_mytest_module_ctx, /* module context */
ngx_http_mytest_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_http_mytest_commands如下,:
static ngx_command_t ngx_http_mytest_commands[] =
{
{
ngx_string("mytest"),
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LMT_CONF | NGX_CONF_NOARGS,
ngx_http_mytest,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL
},
ngx_null_command
};
其中表明当我们遇见了mytest配置项目的时候,将会调用ngx_http_mytest,如下:
static char *
ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *clcf;
//首先找到mytest配置项所属的配置块,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与mytest配置项所在的配置块相匹配,就将调用我们
//实现的ngx_http_mytest_handler方法处理这个请求
clcf->handler = ngx_http_mytest_handler;
return NGX_CONF_OK;
}
其中又调用了 ngx_http_mytest_handler:
static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r){
ngx_http_mytest_ctx_t *myctx = ngx_http_get_module_ctx(r,ngx_http_mytest_module);
if(myctx == NULL){
myctx = ngx_palloc(r->pool,sizeof(ngx_http_mytest_ctx_t));
if(myctx == NULL){
return NGX_ERROR;
}
ngx_http_set_ctx(r,myctx,ngx_http_mytest_module);
}
if(ngx_http_upstream_create(r) != NGX_OK){
ngx_log_error(NGX_LOG_DEBUG,r->connection->log,0,"ngx_http_upstream_create failed");
return NGX_ERROR;
}
//得到配置结构体
ngx_http_mytest_conf_t *mycf = (ngx_http_mytest_conf_t *)ngx_http_get_module_loc_conf(r,ngx_http_mytest_module);
ngx_http_upstream_t *u = r->upstream;
u->conf = &mycf->upstream;
u->buffering = mycf->upstream.buffering;
//resolved 用于存放上游服务器的地址
u->resolved = (ngx_http_upstream_resolved_t *) ngx_palloc(r->pool,sizeof(ngx_http_upstream_resolved_t)