最新消息:

ngx_http_proxy_module 与缓存

nginx admin 3浏览
### 概述
proxy模块是通过ups机制实现了反向代理功能的。该模块非常复杂。
在这里不会说ups机制,除非引入的非常深入。其余的均会带过,了解ups机制请看上篇。
proxy模块通过proxy_cache[_xxx]指令控制proxy缓存。
– 指令:
proxy_cache 是否开启缓存,可以为变量,如果是变量则需要配置proxy_cache_path。
proxy_cache_path 配置缓存的路径,和缓存的策略。
proxy_cache_convert_head 是否把head请求转成get请求缓存。
proxy_cache_bypass 有缓存但是不从缓存获取。bypass。
### 代码
– proxy_cache对应的处理函数ngx_http_proxy_cache。
其作用是是否开启缓存,可以配置变量和常量,如果是变量则该变量的值如果等于proxy_cache_path指令的keys_zone的name,则会走缓存。
如果是常量,则所有的请求都会走缓存。
<br>static char *<br>ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)<br>{<br>ngx_http_proxy_loc_conf_t *plcf = conf;<br>ngx_str_t *value;<br>ngx_http_complex_value_t cv;<br>ngx_http_compile_complex_value_t ccv;<br>value = cf->args->elts;<br>if (plcf->upstream.cache != NGX_CONF_UNSET) {<br>return "is duplicate";<br>}<br>if (ngx_strcmp(value[1].data, "off") == 0) {<br>plcf->upstream.cache = 0;<br>return NGX_CONF_OK;<br>}<br>if (plcf->upstream.store > 0) {<br>return "is incompatible with \"proxy_store\"";<br>}<br>plcf->upstream.cache = 1;<br>ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));<br>ccv.cf = cf;<br>ccv.value = &value[1];<br>ccv.complex_value = &cv;<br>if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {<br>return NGX_CONF_ERROR;<br>}<br>if (cv.lengths != NULL) {<br>// zone 有变量<br>plcf->upstream.cache_value = ngx_palloc(cf->pool,<br>sizeof(ngx_http_complex_value_t));<br>if (plcf->upstream.cache_value == NULL) {<br>return NGX_CONF_ERROR;<br>}<br>*plcf->upstream.cache_value = cv;<br>return NGX_CONF_OK;<br>}<br>// zone 有变量<br>plcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0,<br>&ngx_http_proxy_module);<br>if (plcf->upstream.cache_zone == NULL) {<br>return NGX_CONF_ERROR;<br>}<br>return NGX_CONF_OK;<br>}<br>
– proxy_cache_path 的解析,
<br>struct ngx_http_file_cache_s {<br>ngx_http_file_cache_sh_t *sh;<br>ngx_slab_pool_t *shpool;<br>ngx_path_t *path;<br>off_t max_size;<br>size_t bsize;<br>time_t inactive;<br>time_t fail_time;<br>ngx_uint_t files;<br>ngx_uint_t loader_files;<br>ngx_msec_t last;<br>ngx_msec_t loader_sleep;<br>ngx_msec_t loader_threshold;<br>ngx_uint_t manager_files;<br>ngx_msec_t manager_sleep;<br>ngx_msec_t manager_threshold;<br>ngx_shm_zone_t *shm_zone;<br>ngx_uint_t use_temp_path;<br>/* unsigned use_temp_path:1 */<br>};<br>char *<br>ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)<br>{<br>char *confp = conf;<br>off_t max_size;<br>u_char *last, *p;<br>time_t inactive;<br>ssize_t size;<br>ngx_str_t s, name, *value;<br>ngx_int_t loader_files, manager_files;<br>ngx_msec_t loader_sleep, manager_sleep, loader_threshold,<br>manager_threshold;<br>ngx_uint_t i, n, use_temp_path;<br>ngx_array_t *caches;<br>ngx_http_file_cache_t *cache, **ce;<br>cache = ngx_pcalloc(cf->pool, sizeof(ngx_http_file_cache_t));<br>if (cache == NULL) {<br>return NGX_CONF_ERROR;<br>}<br>cache->path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t));<br>if (cache->path == NULL) {<br>return NGX_CONF_ERROR;<br>}<br>use_temp_path = 1;<br>inactive = 600;<br>loader_files = 100;<br>loader_sleep = 50;<br>loader_threshold = 200;<br>manager_files = 100;<br>manager_sleep = 50;<br>manager_threshold = 200;<br>name.len = 0;<br>size = 0;<br>max_size = NGX_MAX_OFF_T_VALUE;<br>value = cf->args->elts;<br>cache->path->name = value[1];<br>if (cache->path->name.data[cache->path->name.len - 1] == '/') {<br>cache->path->name.len--;<br>}<br>if (ngx_conf_full_name(cf->cycle, &cache->path->name, 0) != NGX_OK) {<br>return NGX_CONF_ERROR;<br>}<br>for (i = 2; i < cf->args->nelts; i++) {<br>if (ngx_strncmp(value[i].data, "levels=", 7) == 0) {<br>p = value[i].data + 7;<br>last = value[i].data + value[i].len;<br>for (n = 0; n < NGX_MAX_PATH_LEVEL && p < last; n++) {<br>if (*p > '0' && *p < '3') {<br>// level[3] 最多3级子目录,每一级子目录长度为1,2。<br>// proxy_cache_path /data/nginx/cache levels=1:2<br>// 最后保存的目录是:/data/nginx/cache/c/29/<br>cache->path->level[n] = *p++ - '0';<br>cache->path->len += cache->path->level[n] + 1;<br>if (p == last) {<br>break;<br>}<br>if (*p++ == ':' && n < NGX_MAX_PATH_LEVEL - 1 && p < last) {<br>continue;<br>}<br>goto invalid_levels;<br>}<br>goto invalid_levels;<br>}<br>// level 小于3级,每级加上分隔符长度为3<br>if (cache->path->len < 10 + NGX_MAX_PATH_LEVEL) {<br>continue;<br>}<br>invalid_levels:<br>ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>"invalid \"levels\" \"%V\"", &value[i]);<br>return NGX_CONF_ERROR;<br>}<br>if (ngx_strncmp(value[i].data, "use_temp_path=", 14) == 0) {<br>if (ngx_strcmp(&value[i].data[14], "on") == 0) {<br>use_temp_path = 1;<br>} else if (ngx_strcmp(&value[i].data[14], "off") == 0) {<br>use_temp_path = 0;<br>} else {<br>ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>"invalid use_temp_path value \"%V\", "<br>"it must be \"on\" or \"off\"",<br>&value[i]);<br>return NGX_CONF_ERROR;<br>}<br>continue;<br>}<br>if (ngx_strncmp(value[i].data, "keys_zone=", 10) == 0) {<br>name.data = value[i].data + 10;<br>p = (u_char *) ngx_strchr(name.data, ':');<br>if (p) {<br>name.len = p - name.data;<br>p++;<br>s.len = value[i].data + value[i].len - p;<br>s.data = p;<br>size = ngx_parse_size(&s);<br>if (size > 8191) {<br>continue;<br>}<br>}<br>ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>"invalid keys zone size \"%V\"", &value[i]);<br>return NGX_CONF_ERROR;<br>}<br>if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {<br>s.len = value[i].len - 9;<br>s.data = value[i].data + 9;<br>inactive = ngx_parse_time(&s, 1);<br>if (inactive == (time_t) NGX_ERROR) {<br>ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>"invalid inactive value \"%V\"", &value[i]);<br>return NGX_CONF_ERROR;<br>}<br>continue;<br>}<br>if (ngx_strncmp(value[i].data, "max_size=", 9) == 0) {<br>s.len = value[i].len - 9;<br>s.data = value[i].data + 9;<br>max_size = ngx_parse_offset(&s);<br>if (max_size < 0) {<br>ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>"invalid max_size value \"%V\"", &value[i]);<br>return NGX_CONF_ERROR;<br>}<br>continue;<br>}<br>if (ngx_strncmp(value[i].data, "loader_files=", 13) == 0) {<br>loader_files = ngx_atoi(value[i].data + 13, value[i].len - 13);<br>if (loader_files == NGX_ERROR) {<br>ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>"invalid loader_files value \"%V\"", &value[i]);<br>return NGX_CONF_ERROR;<br>}<br>continue;<br>}<br>if (ngx_strncmp(value[i].data, "loader_sleep=", 13) == 0) {<br>s.len = value[i].len - 13;<br>s.data = value[i].data + 13;<br>loader_sleep = ngx_parse_time(&s, 0);<br>if (loader_sleep == (ngx_msec_t) NGX_ERROR) {<br>ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>"invalid loader_sleep value \"%V\"", &value[i]);<br>return NGX_CONF_ERROR;<br>}<br>continue;<br>}<br>if (ngx_strncmp(value[i].data, "loader_threshold=", 17) == 0) {<br>s.len = value[i].len - 17;<br>s.data = value[i].data + 17;<br>loader_threshold = ngx_parse_time(&s, 0);<br>if (loader_threshold == (ngx_msec_t) NGX_ERROR) {<br>ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>"invalid loader_threshold value \"%V\"", &value[i]);<br>return NGX_CONF_ERROR;<br>}<br>continue;<br>}<br>if (ngx_strncmp(value[i].data, "manager_files=", 14) == 0) {<br>manager_files = ngx_atoi(value[i].data + 14, value[i].len - 14);<br>if (manager_files == NGX_ERROR) {<br>ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>"invalid manager_files value \"%V\"", &value[i]);<br>return NGX_CONF_ERROR;<br>}<br>continue;<br>}<br>if (ngx_strncmp(value[i].data, "manager_sleep=", 14) == 0) {<br>s.len = value[i].len - 14;<br>s.data = value[i].data + 14;<br>manager_sleep = ngx_parse_time(&s, 0);<br>if (manager_sleep == (ngx_msec_t) NGX_ERROR) {<br>ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>"invalid manager_sleep value \"%V\"", &value[i]);<br>return NGX_CONF_ERROR;<br>}<br>continue;<br>}<br>if (ngx_strncmp(value[i].data, "manager_threshold=", 18) == 0) {<br>s.len = value[i].len - 18;<br>s.data = value[i].data + 18;<br>manager_threshold = ngx_parse_time(&s, 0);<br>if (manager_threshold == (ngx_msec_t) NGX_ERROR) {<br>ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>"invalid manager_threshold value \"%V\"", &value[i]);<br>return NGX_CONF_ERROR;<br>}<br>continue;<br>}<br>ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>"invalid parameter \"%V\"", &value[i]);<br>return NGX_CONF_ERROR;<br>}<br>if (name.len == 0 \|\| size == 0) {<br>ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>"\"%V\" must have \"keys_zone\" parameter",<br>&cmd->name);<br>return NGX_CONF_ERROR;<br>}<br>cache->path->manager = ngx_http_file_cache_manager;<br>cache->path->loader = ngx_http_file_cache_loader;<br>cache->path->data = cache;<br>cache->path->conf_file = cf->conf_file->file.name.data;<br>cache->path->line = cf->conf_file->line;<br>cache->loader_files = loader_files;<br>cache->loader_sleep = loader_sleep;<br>cache->loader_threshold = loader_threshold;<br>cache->manager_files = manager_files;<br>cache->manager_sleep = manager_sleep;<br>cache->manager_threshold = manager_threshold;<br>// 添加到cycle这个结构体的path数组中,由nginx框架统一管理<br>if (ngx_add_path(cf, &cache->path) != NGX_OK) {<br>return NGX_CONF_ERROR;<br>}<br>cache->shm_zone = ngx_shared_memory_add(cf, &name, size, cmd->post);<br>if (cache->shm_zone == NULL) {<br>return NGX_CONF_ERROR;<br>}<br>if (cache->shm_zone->data) {<br>ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>"duplicate zone \"%V\"", &name);<br>return NGX_CONF_ERROR;<br>}<br>cache->shm_zone->init = ngx_http_file_cache_init;<br>cache->shm_zone->data = cache;<br>cache->use_temp_path = use_temp_path;<br>cache->inactive = inactive;<br>cache->max_size = max_size;<br>caches = (ngx_array_t *) (confp + cmd->offset);<br>ce = ngx_array_push(caches);<br>if (ce == NULL) {<br>return NGX_CONF_ERROR;<br>}<br>*ce = cache;<br>return NGX_CONF_OK;<br>}<br>
– proxy_pass 指令解析ngx_http_proxy_pass函数。
<br>static char *<br>ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)<br>{<br>ngx_http_proxy_loc_conf_t *plcf = conf;<br>size_t add;<br>u_short port;<br>ngx_str_t *value, *url;<br>ngx_url_t u;<br>ngx_uint_t n;<br>ngx_http_core_loc_conf_t *clcf;<br>ngx_http_script_compile_t sc;<br>if (plcf->upstream.upstream \|\| plcf->proxy_lengths) {<br>return "is duplicate";<br>}<br>clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);<br>clcf->handler = ngx_http_proxy_handler;<br>if (clcf->name.data[clcf->name.len - 1] == '/') {<br>clcf->auto_redirect = 1;<br>}<br>value = cf->args->elts;<br>url = &value[1];<br>n = ngx_http_script_variables_count(url);<br>if (n) {<br>ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));<br>sc.cf = cf;<br>sc.source = url;<br>sc.lengths = &plcf->proxy_lengths;<br>sc.values = &plcf->proxy_values;<br>sc.variables = n;<br>sc.complete_lengths = 1;<br>sc.complete_values = 1;<br>if (ngx_http_script_compile(&sc) != NGX_OK) {<br>return NGX_CONF_ERROR;<br>}<br>#if (NGX_HTTP_SSL)<br>plcf->ssl = 1;<br>#endif<br>return NGX_CONF_OK;<br>}<br>if (ngx_strncasecmp(url->data, (u_char *) "http://", 7) == 0) {<br>add = 7;<br>port = 80;<br>} else if (ngx_strncasecmp(url->data, (u_char *) "https://", 8) == 0) {<br>#if (NGX_HTTP_SSL)<br>plcf->ssl = 1;<br>add = 8;<br>port = 443;<br>#else<br>ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>"https protocol requires SSL support");<br>return NGX_CONF_ERROR;<br>#endif<br>} else {<br>ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix");<br>return NGX_CONF_ERROR;<br>}<br>ngx_memzero(&u, sizeof(ngx_url_t));<br>u.url.len = url->len - add;<br>u.url.data = url->data + add;<br>u.default_port = port;<br>u.uri_part = 1;<br>u.no_resolve = 1;<br>plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);<br>if (plcf->upstream.upstream == NULL) {<br>return NGX_CONF_ERROR;<br>}<br>plcf->vars.schema.len = add;<br>plcf->vars.schema.data = url->data;<br>plcf->vars.key_start = plcf->vars.schema;<br>ngx_http_proxy_set_vars(&u, &plcf->vars);<br>plcf->location = clcf->name;<br>if (clcf->named<br>#if (NGX_PCRE)<br>\|\| clcf->regex<br>#endif<br>\|\| clcf->noname)<br>{<br>if (plcf->vars.uri.len) {<br>ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>"\"proxy_pass\" cannot have URI part in "<br>"location given by regular expression, "<br>"or inside named location, "<br>"or inside \"if\" statement, "<br>"or inside \"limit_except\" block");<br>return NGX_CONF_ERROR;<br>}<br>plcf->location.len = 0;<br>}<br>plcf->url = *url;<br>return NGX_CONF_OK;<br>}<br>
执行请求的时候会调用ngx_http_proxy_handler函数。
<br>struct ngx_http_upstream_s {<br>ngx_http_upstream_handler_pt read_event_handler;<br>ngx_http_upstream_handler_pt write_event_handler;<br>ngx_peer_connection_t peer;<br>ngx_event_pipe_t *pipe;<br>ngx_chain_t *request_bufs;<br>ngx_output_chain_ctx_t output;<br>ngx_chain_writer_ctx_t writer;<br>ngx_http_upstream_conf_t *conf;<br>ngx_http_upstream_srv_conf_t *upstream;<br>#if (NGX_HTTP_CACHE)<br>ngx_array_t *caches;<br>#endif<br>ngx_http_upstream_headers_in_t headers_in;<br>ngx_http_upstream_resolved_t *resolved;<br>ngx_buf_t from_client;<br>ngx_buf_t buffer;<br>off_t length;<br>ngx_chain_t *out_bufs;<br>ngx_chain_t *busy_bufs;<br>ngx_chain_t *free_bufs;<br>ngx_int_t (*input_filter_init)(void *data);<br>ngx_int_t (*input_filter)(void *data, ssize_t bytes);<br>void *input_filter_ctx;<br>#if (NGX_HTTP_CACHE)<br>// proxy 模块配置为ngx_http_proxy_create_key<br>ngx_int_t (*create_key)(ngx_http_request_t *r);<br>#endif<br>ngx_int_t (*create_request)(ngx_http_request_t *r);<br>ngx_int_t (*reinit_request)(ngx_http_request_t *r);<br>ngx_int_t (*process_header)(ngx_http_request_t *r);<br>void (*abort_request)(ngx_http_request_t *r);<br>void (*finalize_request)(ngx_http_request_t *r,<br>ngx_int_t rc);<br>ngx_int_t (*rewrite_redirect)(ngx_http_request_t *r,<br>ngx_table_elt_t *h, size_t prefix);<br>ngx_int_t (*rewrite_cookie)(ngx_http_request_t *r,<br>ngx_table_elt_t *h);<br>ngx_msec_t timeout;<br>ngx_http_upstream_state_t *state;<br>ngx_str_t method;<br>ngx_str_t schema;<br>ngx_str_t uri;<br>#if (NGX_HTTP_SSL \|\| NGX_COMPAT)<br>ngx_str_t ssl_name;<br>#endif<br>ngx_http_cleanup_pt *cleanup;<br>unsigned store:1;<br>unsigned cacheable:1;<br>unsigned accel:1;<br>unsigned ssl:1;<br>#if (NGX_HTTP_CACHE)<br>unsigned cache_status:3;<br>#endif<br>unsigned buffering:1;<br>unsigned keepalive:1;<br>unsigned upgrade:1;<br>unsigned request_sent:1;<br>unsigned request_body_sent:1;<br>unsigned header_sent:1;<br>};<br>struct ngx_peer_connection_s {<br>ngx_connection_t *connection;<br>struct sockaddr *sockaddr;<br>socklen_t socklen;<br>ngx_str_t *name;<br>ngx_uint_t tries;<br>ngx_msec_t start_time;<br>ngx_event_get_peer_pt get;<br>ngx_event_free_peer_pt free;<br>ngx_event_notify_peer_pt notify;<br>void *data;<br>#if (NGX_SSL \|\| NGX_COMPAT)<br>ngx_event_set_peer_session_pt set_session;<br>ngx_event_save_peer_session_pt save_session;<br>#endif<br>ngx_addr_t *local;<br>int type;<br>int rcvbuf;<br>// 赋值给原请求的log<br>ngx_log_t *log;<br>unsigned cached:1;<br>unsigned transparent:1;<br>/* ngx_connection_log_error_e */<br>unsigned log_error:2;<br>NGX_COMPAT_BEGIN(2)<br>NGX_COMPAT_END<br>};<br>struct ngx_event_pipe_s {<br>ngx_connection_t *upstream;<br>ngx_connection_t *downstream;<br>ngx_chain_t *free_raw_bufs;<br>ngx_chain_t *in;<br>ngx_chain_t **last_in;<br>ngx_chain_t *writing;<br>ngx_chain_t *out;<br>ngx_chain_t *free;<br>ngx_chain_t *busy;<br>/*<br>* the input filter i.e. that moves HTTP/1.1 chunks<br>* from the raw bufs to an incoming chain<br>*/<br>ngx_event_pipe_input_filter_pt input_filter;<br>void *input_ctx;<br>ngx_event_pipe_output_filter_pt output_filter;<br>void *output_ctx;<br>#if (NGX_THREADS \|\| NGX_COMPAT)<br>ngx_int_t (*thread_handler)(ngx_thread_task_t *task,<br>ngx_file_t *file);<br>void *thread_ctx;<br>ngx_thread_task_t *thread_task;<br>#endif<br>unsigned read:1;<br>unsigned cacheable:1;<br>unsigned single_buf:1;<br>unsigned free_bufs:1;<br>unsigned upstream_done:1;<br>unsigned upstream_error:1;<br>unsigned upstream_eof:1;<br>unsigned upstream_blocked:1;<br>unsigned downstream_done:1;<br>unsigned downstream_error:1;<br>unsigned cyclic_temp_file:1;<br>unsigned aio:1;<br>ngx_int_t allocated;<br>ngx_bufs_t bufs;<br>ngx_buf_tag_t tag;<br>ssize_t busy_size;<br>off_t read_length;<br>off_t length;<br>off_t max_temp_file_size;<br>ssize_t temp_file_write_size;<br>ngx_msec_t read_timeout;<br>ngx_msec_t send_timeout;<br>ssize_t send_lowat;<br>ngx_pool_t *pool;<br>ngx_log_t *log;<br>ngx_chain_t *preread_bufs;<br>size_t preread_size;<br>ngx_buf_t *buf_to_file;<br>size_t limit_rate;<br>time_t start_sec;<br>ngx_temp_file_t *temp_file;<br>/* STUB */ int num;<br>};<br>typedef struct {<br>ngx_list_t headers;<br>ngx_uint_t status_n;<br>ngx_str_t status_line;<br>ngx_table_elt_t *status;<br>ngx_table_elt_t *date;<br>ngx_table_elt_t *server;<br>ngx_table_elt_t *connection;<br>ngx_table_elt_t *expires;<br>ngx_table_elt_t *etag;<br>ngx_table_elt_t *x_accel_expires;<br>ngx_table_elt_t *x_accel_redirect;<br>ngx_table_elt_t *x_accel_limit_rate;<br>ngx_table_elt_t *content_type;<br>ngx_table_elt_t *content_length;<br>ngx_table_elt_t *last_modified;<br>ngx_table_elt_t *location;<br>ngx_table_elt_t *accept_ranges;<br>ngx_table_elt_t *www_authenticate;<br>ngx_table_elt_t *transfer_encoding;<br>ngx_table_elt_t *vary;<br>#if (NGX_HTTP_GZIP)<br>ngx_table_elt_t *content_encoding;<br>#endif<br>ngx_array_t cache_control;<br>ngx_array_t cookies;<br>// body 长度<br>off_t content_length_n;<br>// 最后修改时间(http 缓存使用)<br>time_t last_modified_time;<br>unsigned connection_close:1;<br>unsigned chunked:1;<br>} ngx_http_upstream_headers_in_t;<br>
缓存
<br>static ngx_int_t<br>ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u)<br>{<br>ngx_int_t rc;<br>ngx_http_cache_t *c;<br>ngx_http_file_cache_t *cache;<br>c = r->cache;<br>if (c == NULL) {<br>// 是否是定义的缓存的方法<br>if (!(r->method & u->conf->cache_methods)) {<br>return NGX_DECLINED;<br>}<br>// 请求是否要缓存,如果返回NGX_OK 则cache返回要缓存的目录和参数<br>rc = ngx_http_upstream_cache_get(r, u, &cache);<br>if (rc != NGX_OK) {<br>return rc;<br>}<br>if (r->method == NGX_HTTP_HEAD && u->conf->cache_convert_head) {<br>u->method = ngx_http_core_get_method;<br>}<br>if (ngx_http_file_cache_new(r) != NGX_OK) {<br>return NGX_ERROR;<br>}<br>if (u->create_key(r) != NGX_OK) {<br>return NGX_ERROR;<br>}<br>/* TODO: add keys */<br>ngx_http_file_cache_create_key(r);<br>if (r->cache->header_start + 256 >= u->conf->buffer_size) {<br>ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,<br>"%V_buffer_size %uz is not enough for cache key, "<br>"it should be increased to at least %uz",<br>&u->conf->module, u->conf->buffer_size,<br>ngx_align(r->cache->header_start + 256, 1024));<br>r->cache = NULL;<br>return NGX_DECLINED;<br>}<br>u->cacheable = 1;<br>c = r->cache;<br>c->body_start = u->conf->buffer_size;<br>c->min_uses = u->conf->cache_min_uses;<br>c->file_cache = cache;<br>switch (ngx_http_test_predicates(r, u->conf->cache_bypass)) {<br>case NGX_ERROR:<br>return NGX_ERROR;<br>case NGX_DECLINED:<br>u->cache_status = NGX_HTTP_CACHE_BYPASS;<br>return NGX_DECLINED;<br>default: /* NGX_OK */<br>break;<br>}<br>c->lock = u->conf->cache_lock;<br>c->lock_timeout = u->conf->cache_lock_timeout;<br>c->lock_age = u->conf->cache_lock_age;<br>u->cache_status = NGX_HTTP_CACHE_MISS;<br>}<br>// 打开缓存文件<br>rc = ngx_http_file_cache_open(r);<br>ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,<br>"http upstream cache: %i", rc);<br>switch (rc) {<br>case NGX_HTTP_CACHE_STALE:<br>if (((u->conf->cache_use_stale & NGX_HTTP_UPSTREAM_FT_UPDATING)<br>\|\| c->stale_updating) && !r->background<br>&& u->conf->cache_background_update)<br>{<br>r->cache->background = 1;<br>u->cache_status = rc;<br>rc = NGX_OK;<br>}<br>break;<br>case NGX_HTTP_CACHE_UPDATING:<br>if (((u->conf->cache_use_stale & NGX_HTTP_UPSTREAM_FT_UPDATING)<br>\|\| c->stale_updating) && !r->background)<br>{<br>u->cache_status = rc;<br>rc = NGX_OK;<br>} else {<br>rc = NGX_HTTP_CACHE_STALE;<br>}<br>break;<br>case NGX_OK:<br>u->cache_status = NGX_HTTP_CACHE_HIT;<br>}<br>switch (rc) {<br>case NGX_OK:<br>return NGX_OK;<br>case NGX_HTTP_CACHE_STALE:<br>c->valid_sec = 0;<br>c->updating_sec = 0;<br>c->error_sec = 0;<br>u->buffer.start = NULL;<br>u->cache_status = NGX_HTTP_CACHE_EXPIRED;<br>break;<br>case NGX_DECLINED:<br>if ((size_t) (u->buffer.end - u->buffer.start) < u->conf->buffer_size) {<br>u->buffer.start = NULL;<br>} else {<br>u->buffer.pos = u->buffer.start + c->header_start;<br>u->buffer.last = u->buffer.pos;<br>}<br>break;<br>case NGX_HTTP_CACHE_SCARCE:<br>u->cacheable = 0;<br>break;<br>case NGX_AGAIN:<br>return NGX_BUSY;<br>case NGX_ERROR:<br>return NGX_ERROR;<br>default:<br>/* cached NGX_HTTP_BAD_GATEWAY, NGX_HTTP_GATEWAY_TIME_OUT, etc. */<br>u->cache_status = NGX_HTTP_CACHE_HIT;<br>return rc;<br>}<br>if (ngx_http_upstream_cache_check_range(r, u) == NGX_DECLINED) {<br>u->cacheable = 0;<br>}<br>r->cached = 0;<br>return NGX_DECLINED;<br>}<br>

转载请注明:爱开源 » ngx_http_proxy_module 与缓存

转载请注明:爱开源 » ngx_http_proxy_module 与缓存