最新消息:

error_page 指令代码分析

nginx admin 1浏览
### 概述
在nginx中可以通过error_page指令指定错误页面。和error_page 相关的还有recursive_error_pages指令,该指令制定是否递归解析error_page指令的错误页面,例如如下配置,如果recursive_error_pages 为off;则404会解析为405,如果为on,则会解析到406.
<br>error_page 404 =405 /uri;<br>error_page 405 =406 /uri;<br>
### 代码分析
#### 配置解析
error_page是在ngx_http_core_module模块中实现的, 有ngx_http_core_error_page函数处理配置信息。
<br>// 每一个错误码(code)将会对应一个这样的结构体<br>typedef struct {<br>ngx_int_t status; // code<br>ngx_int_t overwrite; // response<br>ngx_http_complex_value_t value; // uri<br>ngx_str_t args; // rui的args<br>} ngx_http_err_page_t;<br>// 格式:error_page code ... [=[response]] uri;<br>static char *<br>ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)<br>{<br>ngx_http_core_loc_conf_t *clcf = conf;<br>u_char *p;<br>ngx_int_t overwrite;<br>ngx_str_t *value, uri, args;<br>ngx_uint_t i, n;<br>ngx_http_err_page_t *err;<br>ngx_http_complex_value_t cv;<br>ngx_http_compile_complex_value_t ccv;<br>if (clcf->error_pages == NULL) {<br>clcf->error_pages = ngx_array_create(cf->pool, 4,<br>sizeof(ngx_http_err_page_t));<br>if (clcf->error_pages == NULL) {<br>return NGX_CONF_ERROR;<br>}<br>}<br>value = cf->args->elts;<br>i = cf->args->nelts - 2;<br>if (value[i].data[0] == '=') {<br>if (i == 1) {<br>ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>"invalid value \"%V\"", &value[i]);<br>return NGX_CONF_ERROR;<br>}<br>if (value[i].len > 1) {<br>overwrite = ngx_atoi(&value[i].data[1], value[i].len - 1);<br>if (overwrite == NGX_ERROR) {<br>ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>"invalid value \"%V\"", &value[i]);<br>return NGX_CONF_ERROR;<br>}<br>} else {<br>overwrite = 0;<br>}<br>n = 2;<br>} else {<br>overwrite = -1;<br>n = 1;<br>}<br>uri = value[cf->args->nelts - 1];<br>ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));<br>ccv.cf = cf;<br>ccv.value = &uri;<br>ccv.complex_value = &cv;<br>if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {<br>return NGX_CONF_ERROR;<br>}<br>ngx_str_null(&args);<br>if (cv.lengths == NULL && uri.len && uri.data[0] == '/') {<br>p = (u_char *) ngx_strchr(uri.data, '?');<br>if (p) {<br>cv.value.len = p - uri.data;<br>cv.value.data = uri.data;<br>p++;<br>args.len = (uri.data + uri.len) - p;<br>args.data = p;<br>}<br>}<br>for (i = 1; i < cf->args->nelts - n; i++) {<br>err = ngx_array_push(clcf->error_pages);<br>if (err == NULL) {<br>return NGX_CONF_ERROR;<br>}<br>err->status = ngx_atoi(value[i].data, value[i].len);<br>if (err->status == NGX_ERROR \|\| err->status == 499) {<br>ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>"invalid value \"%V\"", &value[i]);<br>return NGX_CONF_ERROR;<br>}<br>if (err->status < 300 \|\| err->status > 599) {<br>ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>"value \"%V\" must be between 300 and 599",<br>&value[i]);<br>return NGX_CONF_ERROR;<br>}<br>err->overwrite = overwrite;<br>if (overwrite == -1) {<br>switch (err->status) {<br>case NGX_HTTP_TO_HTTPS:<br>case NGX_HTTPS_CERT_ERROR:<br>case NGX_HTTPS_NO_CERT:<br>err->overwrite = NGX_HTTP_BAD_REQUEST;<br>}<br>}<br>err->value = cv;<br>err->args = args;<br>}<br>return NGX_CONF_OK;<br>}<br>
#### 请求处理
错误页面跳转会调用ngx_http_special_response_handler函数,该函数会调用ngx_http_send_error_page发送错误页面。
<br>ngx_int_t<br>ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error)<br>{<br>ngx_uint_t i, err;<br>ngx_http_err_page_t *err_page;<br>ngx_http_core_loc_conf_t *clcf;<br>ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,<br>"http special response: %i, \"%V?%V\"",<br>error, &r->uri, &r->args);<br>r->err_status = error;<br>if (r->keepalive) {<br>switch (error) {<br>case NGX_HTTP_BAD_REQUEST:<br>case NGX_HTTP_REQUEST_ENTITY_TOO_LARGE:<br>case NGX_HTTP_REQUEST_URI_TOO_LARGE:<br>case NGX_HTTP_TO_HTTPS:<br>case NGX_HTTPS_CERT_ERROR:<br>case NGX_HTTPS_NO_CERT:<br>case NGX_HTTP_INTERNAL_SERVER_ERROR:<br>case NGX_HTTP_NOT_IMPLEMENTED:<br>r->keepalive = 0;<br>}<br>}<br>if (r->lingering_close) {<br>switch (error) {<br>case NGX_HTTP_BAD_REQUEST:<br>case NGX_HTTP_TO_HTTPS:<br>case NGX_HTTPS_CERT_ERROR:<br>case NGX_HTTPS_NO_CERT:<br>r->lingering_close = 0;<br>}<br>}<br>r->headers_out.content_type.len = 0;<br>clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);<br>if (!r->error_page && clcf->error_pages && r->uri_changes != 0) {<br>// 是否递归解析错误页面<br>if (clcf->recursive_error_pages == 0) {<br>r->error_page = 1;<br>}<br>err_page = clcf->error_pages->elts;<br>for (i = 0; i < clcf->error_pages->nelts; i++) {<br>if (err_page[i].status == error) {<br>return ngx_http_send_error_page(r, &err_page[i]);<br>}<br>}<br>}<br>r->expect_tested = 1;<br>if (ngx_http_discard_request_body(r) != NGX_OK) {<br>r->keepalive = 0;<br>}<br>if (clcf->msie_refresh<br>&& r->headers_in.msie<br>&& (error == NGX_HTTP_MOVED_PERMANENTLY<br>\|\| error == NGX_HTTP_MOVED_TEMPORARILY))<br>{<br>return ngx_http_send_refresh(r);<br>}<br>if (error == NGX_HTTP_CREATED) {<br>/* 201 */<br>err = 0;<br>} else if (error == NGX_HTTP_NO_CONTENT) {<br>/* 204 */<br>err = 0;<br>} else if (error >= NGX_HTTP_MOVED_PERMANENTLY<br>&& error < NGX_HTTP_LAST_3XX)<br>{<br>/* 3XX */<br>err = error - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_OFF_3XX;<br>} else if (error >= NGX_HTTP_BAD_REQUEST<br>&& error < NGX_HTTP_LAST_4XX)<br>{<br>/* 4XX */<br>err = error - NGX_HTTP_BAD_REQUEST + NGX_HTTP_OFF_4XX;<br>} else if (error >= NGX_HTTP_NGINX_CODES<br>&& error < NGX_HTTP_LAST_5XX)<br>{<br>/* 49X, 5XX */<br>err = error - NGX_HTTP_NGINX_CODES + NGX_HTTP_OFF_5XX;<br>switch (error) {<br>case NGX_HTTP_TO_HTTPS:<br>case NGX_HTTPS_CERT_ERROR:<br>case NGX_HTTPS_NO_CERT:<br>case NGX_HTTP_REQUEST_HEADER_TOO_LARGE:<br>r->err_status = NGX_HTTP_BAD_REQUEST;<br>}<br>} else {<br>/* unknown code, zero body */<br>err = 0;<br>}<br>return ngx_http_send_special_response(r, clcf, err);<br>}<br>static ngx_int_t<br>ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page)<br>{<br>ngx_int_t overwrite;<br>ngx_str_t uri, args;<br>ngx_table_elt_t *location;<br>ngx_http_core_loc_conf_t *clcf;<br>overwrite = err_page->overwrite;<br>if (overwrite && overwrite != NGX_HTTP_OK) {<br>r->expect_tested = 1;<br>}<br>// 覆盖的状态码<br>if (overwrite >= 0) {<br>r->err_status = overwrite;<br>}<br>if (ngx_http_complex_value(r, &err_page->value, &uri) != NGX_OK) {<br>return NGX_ERROR;<br>}<br>if (uri.len && uri.data[0] == '/') {<br>if (err_page->value.lengths) {<br>ngx_http_split_args(r, &uri, &args);<br>} else {<br>args = err_page->args;<br>}<br>if (r->method != NGX_HTTP_HEAD) {<br>r->method = NGX_HTTP_GET;<br>r->method_name = ngx_http_core_get_method;<br>}<br>return ngx_http_internal_redirect(r, &uri, &args);<br>}<br>if (uri.len && uri.data[0] == '@') {<br>return ngx_http_named_location(r, &uri);<br>}<br>location = ngx_list_push(&r->headers_out.headers);<br>if (location == NULL) {<br>return NGX_ERROR;<br>}<br>if (overwrite != NGX_HTTP_MOVED_PERMANENTLY<br>&& overwrite != NGX_HTTP_MOVED_TEMPORARILY<br>&& overwrite != NGX_HTTP_SEE_OTHER<br>&& overwrite != NGX_HTTP_TEMPORARY_REDIRECT<br>&& overwrite != NGX_HTTP_PERMANENT_REDIRECT)<br>{<br>r->err_status = NGX_HTTP_MOVED_TEMPORARILY;<br>}<br>location->hash = 1;<br>ngx_str_set(&location->key, "Location");<br>location->value = uri;<br>ngx_http_clear_location(r);<br>r->headers_out.location = location;<br>clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);<br>if (clcf->msie_refresh && r->headers_in.msie) {<br>return ngx_http_send_refresh(r);<br>}<br>return ngx_http_send_special_response(r, clcf, r->err_status<br>- NGX_HTTP_MOVED_PERMANENTLY<br>+ NGX_HTTP_OFF_3XX);<br>}<br>

FROM:https://github.com/vislee/leevis.com/issues/131

相关文章

转载请注明:爱开源 » error_page 指令代码分析

转载请注明:爱开源 » error_page 指令代码分析