基本含义
- $bytes_sent(1.3.8, 1.2.5):nginx返回给客户端的字节数,包括响应头和响应体。
- $body_bytes_sent:nginx返回给客户端的响应体的字节数(即不含响应头)。
- $content_length:“Content-Length”请求头的值,等同于$http_content_length。即,nginx从客户端收到的请求头中Content-Length字段的值,不是nginx返回给客户端响应中的Content-Length字段($sent_http_content_length)的值。
- $request_length(1.3.12, 1.2.7):请求的字节数(包括请求行、请求头和请求体)。注意,由于$request_length是请求解析过程中不断累加的,如果解析请求时出现异常或提前完成,则$request_length只是已经累加部分的长度,并不是nginx从客户端收到的完整请求的总字节数(包括请求行、请求头、请求体)。例如,向nginx的静态文件的URL POST数据,则POST的数据(即请求体)不会计算在内。
- $upstream_response_length(0.7.27):保存从upstream服务器获得的响应体的字节数,不包括响应头,1.11.4中增加的$upstream_bytes_received变量是包括响应头的。如果有多个响应长度的话使用逗号和冒号分隔,就像$upstream_addr中的地址那样。
代码分析
注:代码版本是nginx-1.10.2
$bytes_sent
变量处理代码:
static ngx_int_t
ngx_http_variable_bytes_sent(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
u_char *p;
p = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);
if (p == NULL) {
return NGX_ERROR;
}
v->len = ngx_sprintf(p, "%O", r->connection->sent) - p;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = p;
return NGX_OK;
}
从代码中可以看出$bytes_sent就是r->connection->sent,真正发送给客户端的全部的字节数。
$body_bytes_sent
变量处理代码:
static ngx_int_t
ngx_http_variable_body_bytes_sent(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
off_t sent;
u_char *p;
sent = r->connection->sent - r->header_size;
if (sent < 0) {
sent = 0;
}
p = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);
if (p == NULL) {
return NGX_ERROR;
}
v->len = ngx_sprintf(p, "%O", sent) - p;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = p;
return NGX_OK;
}
从代码中可以看出$body_bytes_sent就是r->connection->sent减去r->header_size(响应头),即响应体的字节数。
$content_length
变量处理代码:
static ngx_int_t
ngx_http_variable_content_length(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
u_char *p;
if (r->headers_in.content_length) {
v->len = r->headers_in.content_length->value.len;
v->data = r->headers_in.content_length->value.data;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
} else if (r->reading_body) {
v->not_found = 1;
v->no_cacheable = 1;
} else if (r->headers_in.content_length_n >= 0) {
p = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);
if (p == NULL) {
return NGX_ERROR;
}
v->len = ngx_sprintf(p, "%O", r->headers_in.content_length_n) - p;
v->data = p;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
} else {
v->not_found = 1;
}
return NGX_OK;
}
$content_length是r->headers_in中的content_length或content_length_n的值,不是r->headers_out中的content_length,所以是接收的请求的Content-Length。
$request_length
变量处理代码:
static ngx_int_t
ngx_http_variable_request_length(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
u_char *p;
p = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);
if (p == NULL) {
return NGX_ERROR;
}
v->len = ngx_sprintf(p, "%O", r->request_length) - p;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = p;
return NGX_OK;
}
$request_length就是r->request_length的值
解析请求行代码:
rc = ngx_http_parse_request_line(r, r->header_in);
if (rc == NGX_OK) {
/* the request line has been parsed successfully */
r->request_line.len = r->request_end - r->request_start;
r->request_line.data = r->request_start;
r->request_length = r->header_in->pos - r->request_start;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http request line: \"%V\"", &r->request_line);
r->method_name.len = r->method_end - r->request_start + 1;
r->method_name.data = r->request_line.data;
......
}
r->request_length初始化为请求行的长度。
处理请求头的代码:
for ( ;; ) {
......
if (rc == NGX_OK) {
r->request_length += r->header_in->pos - r->header_name_start;
......
/* a header line has been parsed successfully */
h = ngx_list_push(&r->headers_in.headers);
......
continue;
}
if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
/* a whole header has been parsed successfully */
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http header done");
r->request_length += r->header_in->pos - r->header_name_start;
r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE;
rc = ngx_http_process_request_header(r);
if (rc != NGX_OK) {
return;
}
ngx_http_process_request(r);
return;
}
......
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
return;
}
循环解析请求头时,不断累加r->request_length。
处理pre-read请求体代码:
preread = r->header_in->last - r->header_in->pos;
if (preread) {
/* there is the pre-read part of the request body */
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http client request body preread %uz", preread);
out.buf = r->header_in;
out.next = NULL;
rc = ngx_http_request_body_filter(r, &out);
if (rc != NGX_OK) {
goto done;
}
r->request_length += preread - (r->header_in->last - r->header_in->pos);
......
}
r->request_length累加上pre-read请求体长度。
处理请求体代码:
static ngx_int_t
ngx_http_do_read_client_request_body(ngx_http_request_t *r)
{
......
for ( ;; ) {
for ( ;; ) {
......
n = c->recv(c, rb->buf->last, size);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http client request body recv %z", n);
if (n == NGX_AGAIN) {
break;
}
if (n == 0) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"client prematurely closed connection");
}
if (n == 0 || n == NGX_ERROR) {
c->error = 1;
return NGX_HTTP_BAD_REQUEST;
}
rb->buf->last += n;
r->request_length += n;
......
}
......
}
......
}
r->request_length累加读取的请求体长度。
$upstream_response_length
变量处理代码:
static ngx_int_t
ngx_http_upstream_response_length_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
u_char *p;
size_t len;
ngx_uint_t i;
ngx_http_upstream_state_t *state;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
v->not_found = 1;
return NGX_OK;
}
len = r->upstream_states->nelts * (NGX_OFF_T_LEN + 2);
p = ngx_pnalloc(r->pool, len);
if (p == NULL) {
return NGX_ERROR;
}
v->data = p;
i = 0;
state = r->upstream_states->elts;
for ( ;; ) {
p = ngx_sprintf(p, "%O", state[i].response_length);
if (++i == r->upstream_states->nelts) {
break;
}
if (state[i].peer) {
*p++ = ',';
*p++ = ' ';
} else {
*p++ = ' ';
*p++ = ':';
*p++ = ' ';
if (++i == r->upstream_states->nelts) {
break;
}
continue;
}
}
v->len = p - v->data;
return NGX_OK;
}
ngx_http_upstream_state_t结构体代码:
typedef struct {
ngx_msec_t bl_time;
ngx_uint_t bl_state;
ngx_uint_t status;
ngx_msec_t response_time;
ngx_msec_t connect_time;
ngx_msec_t header_time;
off_t response_length;
ngx_str_t *peer;
} ngx_http_upstream_state_t;
$upstream_response_length就是遍历r->upstream_states(nginx数组),取出ngx_http_upstream_state_t中的response_length。upstream处理过程中,将后端响应信息存入r->upstream->state(ngx_http_upstream_state_t类型,实际存储在r->upstream_states数组中)中。如果请求了多次后端server,后端响应信息顺序保存在r->upstream_states数组中,数组中的最后一个元素,也就是r->upstream->state,保存着最后一次请求后端server的响应信息。